carapace-plugin-sdk 1.0.0 → 1.0.1
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/LICENSE +21 -21
- package/dist/generate-cli.js +11 -0
- package/dist/generate-cli.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +58 -54
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Jeff Steinbok
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jeff Steinbok
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/generate-cli.js
CHANGED
|
@@ -55,9 +55,17 @@ export default createAdapter(createEntry(), import.meta.url);
|
|
|
55
55
|
}
|
|
56
56
|
function generateManifest(pluginEntry) {
|
|
57
57
|
let version = "0.0.0";
|
|
58
|
+
let source = void 0;
|
|
58
59
|
try {
|
|
59
60
|
const pkg = JSON.parse(readFileSync(resolve(process.cwd(), "package.json"), "utf8"));
|
|
60
61
|
version = pkg.version ?? version;
|
|
62
|
+
if (pkg.repository) {
|
|
63
|
+
const repo = typeof pkg.repository === "string" ? pkg.repository : pkg.repository.url ?? "";
|
|
64
|
+
const match = repo.match(/(?:github\.com[/:]|^github:)([^/]+\/[^/.]+)/);
|
|
65
|
+
if (match) {
|
|
66
|
+
source = { canonicalRepo: match[1] };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
61
69
|
} catch {
|
|
62
70
|
console.warn("Warning: could not read package.json for version \u2014 defaulting to 0.0.0");
|
|
63
71
|
}
|
|
@@ -76,6 +84,9 @@ function generateManifest(pluginEntry) {
|
|
|
76
84
|
manifest.contracts = pluginEntry.contracts;
|
|
77
85
|
}
|
|
78
86
|
manifest.activation = pluginEntry.activation ?? { onStartup: true };
|
|
87
|
+
if (source) {
|
|
88
|
+
manifest.source = source;
|
|
89
|
+
}
|
|
79
90
|
manifest.openclaw = {};
|
|
80
91
|
const outPath = resolve(process.cwd(), "openclaw.plugin.json");
|
|
81
92
|
writeFileSync(outPath, JSON.stringify(manifest, null, 2) + "\n");
|
package/dist/generate-cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/generate-cli.ts"],"sourcesContent":["#!/usr/bin/env node\
|
|
1
|
+
{"version":3,"sources":["../src/generate-cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * carapace-generate-cli — Build-time generator for OpenClaw plugins.\n *\n * Reads a plugin's createEntry() metadata and emits:\n * - dist/bin/<plugin-id>.js — standalone CLI entry point\n * - dist/adapter.js — OpenClaw adapter (always identical, no source file needed)\n * - openclaw.plugin.json — plugin manifest (derived from createEntry() + package.json)\n *\n * Usage:\n * carapace-generate-cli --entry ./dist/plugin.js --out ./dist/bin\n * carapace-generate-cli --entry ./dist/plugin.js --out ./dist/bin --name my-tool\n */\n\nimport { writeFileSync, mkdirSync, readFileSync } from \"node:fs\";\nimport { resolve, relative, dirname, sep } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\n\n// ---------------------------------------------------------------------------\n// Arg parsing\n// ---------------------------------------------------------------------------\n\nfunction parseGeneratorArgs(): { entry: string; outDir: string; name?: string } {\n const args = process.argv.slice(2);\n let entry = \"\";\n let outDir = \"\";\n let name: string | undefined;\n\n for (let i = 0; i < args.length; i++) {\n if (args[i] === \"--entry\" && args[i + 1]) entry = args[++i];\n else if (args[i] === \"--out\" && args[i + 1]) outDir = args[++i];\n else if (args[i] === \"--name\" && args[i + 1]) name = args[++i];\n }\n\n if (!entry || !outDir) {\n console.error(\"Usage: carapace-generate-cli --entry <path-to-dist/index.js> --out <output-dir> [--name <bin-name>]\");\n process.exit(1);\n }\n\n return { entry: resolve(entry), outDir: resolve(outDir), name };\n}\n\n// ---------------------------------------------------------------------------\n// Path helper\n// ---------------------------------------------------------------------------\n\nfunction toPosixRelative(from: string, to: string): string {\n let rel = relative(from, to);\n if (sep === \"\\\\\") rel = rel.replaceAll(\"\\\\\", \"/\");\n if (!rel.startsWith(\".\")) rel = `./${rel}`;\n return rel;\n}\n\n// ---------------------------------------------------------------------------\n// Generators\n// ---------------------------------------------------------------------------\n\nfunction generateCli(entry: string, outDir: string, binName: string, envPrefix: string): void {\n const relativeEntry = toPosixRelative(outDir, entry);\n\n const content = `#!/usr/bin/env node\n// Auto-generated by carapace-plugin-sdk — do not edit\nimport { run } from \"carapace-plugin-sdk/cli\";\nimport { createEntry } from \"${relativeEntry}\";\n\nrun(createEntry(), { binName: \"${binName}\", envPrefix: \"${envPrefix}\" });\n`;\n\n mkdirSync(outDir, { recursive: true });\n const outPath = resolve(outDir, `${binName}.js`);\n writeFileSync(outPath, content, { mode: 0o755 });\n console.log(`Generated CLI: ${outPath}`);\n}\n\nfunction generateAdapter(entry: string): void {\n const adapterDir = dirname(entry);\n const relativeEntry = toPosixRelative(adapterDir, entry);\n\n const content = `// Auto-generated by carapace-plugin-sdk — do not edit\nimport { createAdapter } from \"carapace-plugin-sdk\";\nimport { createEntry } from \"${relativeEntry}\";\n\nexport default createAdapter(createEntry(), import.meta.url);\n`;\n\n const outPath = resolve(adapterDir, \"adapter.js\");\n writeFileSync(outPath, content);\n console.log(`Generated adapter: ${outPath}`);\n}\n\n/**\n * Generate openclaw.plugin.json from createEntry() metadata + package.json.\n *\n * createEntry() is the single source of truth for:\n * id, name, description, configSchema, contracts, activation\n *\n * version comes from package.json (it's the npm package version).\n * entry is always ./dist/adapter.js.\n *\n * The manifest is written to the current working directory (the plugin root),\n * not into dist/, because OpenClaw reads it from the installed package root.\n */\nfunction generateManifest(pluginEntry: {\n id: string;\n name: string;\n description?: string;\n configSchema?: unknown;\n contracts?: unknown;\n activation?: unknown;\n}): void {\n // Read version from package.json in the plugin's root directory.\n // process.cwd() is the plugin root when invoked via `npm run build`.\n let version = \"0.0.0\";\n let source: unknown = undefined;\n try {\n const pkg = JSON.parse(readFileSync(resolve(process.cwd(), \"package.json\"), \"utf8\"));\n version = pkg.version ?? version;\n if (pkg.repository) {\n // Derive source from package.json repository field\n const repo = typeof pkg.repository === \"string\" ? pkg.repository : pkg.repository.url ?? \"\";\n const match = repo.match(/(?:github\\.com[/:]|^github:)([^/]+\\/[^/.]+)/);\n if (match) {\n source = { canonicalRepo: match[1] };\n }\n }\n } catch {\n console.warn(\"Warning: could not read package.json for version — defaulting to 0.0.0\");\n }\n\n const manifest: Record<string, unknown> = {\n id: pluginEntry.id,\n name: pluginEntry.name,\n description: pluginEntry.description ?? \"\",\n version,\n // The adapter is always at this path — generated by generateAdapter() above.\n entry: \"./dist/adapter.js\",\n };\n\n if (pluginEntry.configSchema) {\n manifest.configSchema = pluginEntry.configSchema;\n }\n\n if (pluginEntry.contracts) {\n manifest.contracts = pluginEntry.contracts;\n }\n\n // activation defaults to onStartup: true if not specified.\n manifest.activation = pluginEntry.activation ?? { onStartup: true };\n\n if (source) {\n manifest.source = source;\n }\n\n // openclaw is a host-specific extension block. Default to empty.\n manifest.openclaw = {};\n\n const outPath = resolve(process.cwd(), \"openclaw.plugin.json\");\n writeFileSync(outPath, JSON.stringify(manifest, null, 2) + \"\\n\");\n console.log(`Generated manifest: ${outPath}`);\n}\n\n// ---------------------------------------------------------------------------\n// Main\n// ---------------------------------------------------------------------------\n\nasync function main() {\n const { entry, outDir, name } = parseGeneratorArgs();\n\n const entryUrl = pathToFileURL(entry).href;\n const mod = await import(entryUrl);\n\n const createEntry = mod.createEntry ?? mod.default?.createEntry;\n if (typeof createEntry !== \"function\") {\n console.error(`Error: ${entry} does not export createEntry()`);\n process.exit(1);\n }\n\n const pluginEntry = createEntry();\n const binName = name ?? pluginEntry.id;\n const envPrefix = binName.replace(/-/g, \"_\").toUpperCase();\n\n generateCli(entry, outDir, binName, envPrefix);\n generateAdapter(entry);\n generateManifest(pluginEntry);\n}\n\nmain().catch((e) => {\n console.error(e);\n process.exit(1);\n});\n"],"mappings":";;;AAcA,SAAS,eAAe,WAAW,oBAAoB;AACvD,SAAS,SAAS,UAAU,SAAS,WAAW;AAChD,SAAS,qBAAqB;AAM9B,SAAS,qBAAuE;AAC9E,QAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,MAAI,QAAQ;AACZ,MAAI,SAAS;AACb,MAAI;AAEJ,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,QAAI,KAAK,CAAC,MAAM,aAAa,KAAK,IAAI,CAAC,EAAG,SAAQ,KAAK,EAAE,CAAC;AAAA,aACjD,KAAK,CAAC,MAAM,WAAW,KAAK,IAAI,CAAC,EAAG,UAAS,KAAK,EAAE,CAAC;AAAA,aACrD,KAAK,CAAC,MAAM,YAAY,KAAK,IAAI,CAAC,EAAG,QAAO,KAAK,EAAE,CAAC;AAAA,EAC/D;AAEA,MAAI,CAAC,SAAS,CAAC,QAAQ;AACrB,YAAQ,MAAM,qGAAqG;AACnH,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,SAAO,EAAE,OAAO,QAAQ,KAAK,GAAG,QAAQ,QAAQ,MAAM,GAAG,KAAK;AAChE;AAMA,SAAS,gBAAgB,MAAc,IAAoB;AACzD,MAAI,MAAM,SAAS,MAAM,EAAE;AAC3B,MAAI,QAAQ,KAAM,OAAM,IAAI,WAAW,MAAM,GAAG;AAChD,MAAI,CAAC,IAAI,WAAW,GAAG,EAAG,OAAM,KAAK,GAAG;AACxC,SAAO;AACT;AAMA,SAAS,YAAY,OAAe,QAAgB,SAAiB,WAAyB;AAC5F,QAAM,gBAAgB,gBAAgB,QAAQ,KAAK;AAEnD,QAAM,UAAU;AAAA;AAAA;AAAA,+BAGa,aAAa;AAAA;AAAA,iCAEX,OAAO,kBAAkB,SAAS;AAAA;AAGjE,YAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;AACrC,QAAM,UAAU,QAAQ,QAAQ,GAAG,OAAO,KAAK;AAC/C,gBAAc,SAAS,SAAS,EAAE,MAAM,IAAM,CAAC;AAC/C,UAAQ,IAAI,sBAAsB,OAAO,EAAE;AAC7C;AAEA,SAAS,gBAAgB,OAAqB;AAC5C,QAAM,aAAa,QAAQ,KAAK;AAChC,QAAM,gBAAgB,gBAAgB,YAAY,KAAK;AAEvD,QAAM,UAAU;AAAA;AAAA,+BAEa,aAAa;AAAA;AAAA;AAAA;AAK1C,QAAM,UAAU,QAAQ,YAAY,YAAY;AAChD,gBAAc,SAAS,OAAO;AAC9B,UAAQ,IAAI,sBAAsB,OAAO,EAAE;AAC7C;AAcA,SAAS,iBAAiB,aAOjB;AAGP,MAAI,UAAU;AACd,MAAI,SAAkB;AACtB,MAAI;AACF,UAAM,MAAM,KAAK,MAAM,aAAa,QAAQ,QAAQ,IAAI,GAAG,cAAc,GAAG,MAAM,CAAC;AACnF,cAAU,IAAI,WAAW;AACzB,QAAI,IAAI,YAAY;AAElB,YAAM,OAAO,OAAO,IAAI,eAAe,WAAW,IAAI,aAAa,IAAI,WAAW,OAAO;AACzF,YAAM,QAAQ,KAAK,MAAM,6CAA6C;AACtE,UAAI,OAAO;AACT,iBAAS,EAAE,eAAe,MAAM,CAAC,EAAE;AAAA,MACrC;AAAA,IACF;AAAA,EACF,QAAQ;AACN,YAAQ,KAAK,6EAAwE;AAAA,EACvF;AAEA,QAAM,WAAoC;AAAA,IACxC,IAAI,YAAY;AAAA,IAChB,MAAM,YAAY;AAAA,IAClB,aAAa,YAAY,eAAe;AAAA,IACxC;AAAA;AAAA,IAEA,OAAO;AAAA,EACT;AAEA,MAAI,YAAY,cAAc;AAC5B,aAAS,eAAe,YAAY;AAAA,EACtC;AAEA,MAAI,YAAY,WAAW;AACzB,aAAS,YAAY,YAAY;AAAA,EACnC;AAGA,WAAS,aAAa,YAAY,cAAc,EAAE,WAAW,KAAK;AAElE,MAAI,QAAQ;AACV,aAAS,SAAS;AAAA,EACpB;AAGA,WAAS,WAAW,CAAC;AAErB,QAAM,UAAU,QAAQ,QAAQ,IAAI,GAAG,sBAAsB;AAC7D,gBAAc,SAAS,KAAK,UAAU,UAAU,MAAM,CAAC,IAAI,IAAI;AAC/D,UAAQ,IAAI,uBAAuB,OAAO,EAAE;AAC9C;AAMA,eAAe,OAAO;AACpB,QAAM,EAAE,OAAO,QAAQ,KAAK,IAAI,mBAAmB;AAEnD,QAAM,WAAW,cAAc,KAAK,EAAE;AACtC,QAAM,MAAM,MAAM,OAAO;AAEzB,QAAM,cAAc,IAAI,eAAe,IAAI,SAAS;AACpD,MAAI,OAAO,gBAAgB,YAAY;AACrC,YAAQ,MAAM,UAAU,KAAK,gCAAgC;AAC7D,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,cAAc,YAAY;AAChC,QAAM,UAAU,QAAQ,YAAY;AACpC,QAAM,YAAY,QAAQ,QAAQ,MAAM,GAAG,EAAE,YAAY;AAEzD,cAAY,OAAO,QAAQ,SAAS,SAAS;AAC7C,kBAAgB,KAAK;AACrB,mBAAiB,WAAW;AAC9B;AAEA,KAAK,EAAE,MAAM,CAAC,MAAM;AAClB,UAAQ,MAAM,CAAC;AACf,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":[]}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\r\n * carapace-plugin-sdk — Core types and helpers for OpenClaw plugins.\r\n *\r\n * This is the main entry point. Import `definePlugin` to author a plugin\r\n * with full TypeScript inference — typed config and typed tool parameters\r\n * with no boilerplate.\r\n *\r\n * Quick-start:\r\n *\r\n * src/plugin.ts — the only file you write; export `createEntry` from `definePlugin`\r\n * dist/adapter.js — auto-generated at build time; do not write by hand\r\n *\r\n * @module carapace-plugin-sdk\r\n */\r\n\r\nimport { createRequire } from \"node:module\";\r\nimport { type TObject, type Static } from \"@sinclair/typebox\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// definePlugin — the primary authoring API\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Internal (erased) tool definition stored at runtime.\r\n * The typed version lives only in TypeScript's type system via ToolFactory<TConfig>.\r\n */\r\ninterface ToolDef {\r\n name: string;\r\n label?: string;\r\n description: string;\r\n parameters: unknown;\r\n execute(params: Record<string, unknown>, config: unknown): Promise<unknown>;\r\n}\r\n\r\n/**\r\n * Typed tool factory injected into the `tools` callback of `definePlugin`.\r\n *\r\n * TConfig is fixed by the enclosing `definePlugin` call, so every tool in the\r\n * array receives the same config type. TSchema is inferred per tool from the\r\n * `parameters` field, giving typed `params` in `execute`.\r\n *\r\n * You never construct this directly — it is passed to you by `definePlugin`.\r\n */\r\ntype ToolFactory<TConfig> = <TSchema extends TObject>(def: {\r\n /** Machine-readable name, used as the CLI subcommand. snake_case recommended. */\r\n name: string;\r\n /** Human-readable label shown in OpenClaw's UI. Defaults to `name`. */\r\n label?: string;\r\n /** One-sentence description shown in --help and OpenClaw's tool inspector. */\r\n description: string;\r\n /**\r\n * TypeBox schema for the tool's parameters.\r\n * The type is inferred as `Static<TSchema>` in `execute`'s first argument.\r\n */\r\n parameters: TSchema;\r\n /**\r\n * The tool's implementation.\r\n *\r\n * @param params - Typed parameters derived from `parameters` schema. No casts needed.\r\n * @param config - Typed config derived from `definePlugin`'s `configSchema`. No casts needed.\r\n * @returns Any JSON-serialisable value. The SDK wraps it in the OpenClaw result format.\r\n */\r\n execute(params: Static<TSchema>, config: TConfig): Promise<unknown>;\r\n}) => ToolDef;\r\n\r\n/**\r\n * Define an OpenClaw plugin with full TypeScript inference.\r\n *\r\n * Returns a `createEntry` function — export it from your `src/index.ts`.\r\n * The SDK handles all registration, result wrapping, and config plumbing.\r\n *\r\n * Config type is inferred from `configSchema` and flows into every tool's\r\n * `execute(params, config)` without any manual type annotations.\r\n *\r\n * @example\r\n * // src/index.ts — the entire plugin\r\n * import { definePlugin } from \"carapace-plugin-sdk\";\r\n * import { Type } from \"@sinclair/typebox\";\r\n *\r\n * export const createEntry = definePlugin({\r\n * id: \"my-plugin\",\r\n * name: \"My Plugin\",\r\n * configSchema: Type.Object({\r\n * apiKey: Type.Optional(Type.String({ description: \"API key.\" })),\r\n * }),\r\n * tools: (tool) => [\r\n * tool({\r\n * name: \"do_thing\",\r\n * description: \"Does the thing.\",\r\n * parameters: Type.Object({\r\n * input: Type.String({ description: \"Input value.\" }),\r\n * }),\r\n * execute: async ({ input }, config) => {\r\n * // input: string ✓ config.apiKey: string | undefined ✓\r\n * return { result: input };\r\n * },\r\n * }),\r\n * ],\r\n * });\r\n */\r\nexport function definePlugin<TConfigSchema extends TObject = TObject>(def: {\r\n /** Unique plugin id. Lowercase alphanumeric with hyphens. Used as the CLI binary name. */\r\n id: string;\r\n /** Human-readable display name. */\r\n name: string;\r\n /** One-sentence description of what the plugin does. */\r\n description?: string;\r\n /** When to load the plugin. Defaults to `{ onStartup: true }`. */\r\n activation?: { onStartup?: boolean };\r\n /**\r\n * TypeBox schema for the plugin's config block.\r\n *\r\n * Used for three things simultaneously:\r\n * 1. Runtime JSON Schema for the OpenClaw manifest (validated before register())\r\n * 2. TypeScript type inference for `config` in every tool's `execute`\r\n * 3. Environment variable mapping for the standalone CLI\r\n */\r\n configSchema?: TConfigSchema;\r\n /**\r\n * Declare your tools here. Receives a typed `tool()` factory as its argument.\r\n *\r\n * Using a callback (rather than a plain array) is what allows TypeScript to\r\n * thread the config type through to each tool's `execute` function.\r\n */\r\n tools: (tool: ToolFactory<Static<TConfigSchema>>) => ToolDef[];\r\n}): () => PluginEntry {\r\n return () => {\r\n // The factory is identity at runtime — all type magic is compile-time only.\r\n const toolFactory = ((toolDef: unknown) => toolDef) as ToolFactory<Static<TConfigSchema>>;\r\n const toolDefs = def.tools(toolFactory);\r\n\r\n return {\r\n id: def.id,\r\n name: def.name,\r\n description: def.description,\r\n activation: def.activation ?? { onStartup: true },\r\n // Derive contracts from the declared tools so the manifest is always accurate.\r\n contracts: { tools: toolDefs.map((t) => t.name) },\r\n // TypeBox TObject is valid JSON Schema — pass through for the manifest generator.\r\n configSchema: def.configSchema as unknown as PluginEntry[\"configSchema\"],\r\n register(api: PluginApi) {\r\n // OpenClaw validates pluginConfig against configSchema before calling register(),\r\n // so this cast is safe. Fall back to empty object if config is not yet set.\r\n const config = (api.pluginConfig ?? {}) as Static<TConfigSchema>;\r\n\r\n for (const toolDef of toolDefs) {\r\n api.registerTool({\r\n name: toolDef.name,\r\n label: toolDef.label ?? toolDef.name,\r\n description: toolDef.description,\r\n parameters: toolDef.parameters,\r\n // Wrap the result automatically — execute() returns plain values, not formatResult().\r\n execute: async (_toolCallId: string, params: Record<string, unknown>) =>\r\n formatResult(await toolDef.execute(params, config)),\r\n });\r\n }\r\n },\r\n };\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Low-level types — the plugin contract\r\n//\r\n// These are used by the generated adapter and by advanced plugins that need\r\n// more control than definePlugin provides (e.g. dynamic tool registration).\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * The API object passed to your plugin's `register()` function.\r\n *\r\n * When using `definePlugin`, you never see this directly — the SDK handles it.\r\n * It is exported for advanced use cases and for the generated adapter.\r\n */\r\nexport type PluginApi = {\r\n /** Register a tool with OpenClaw. Call once per tool inside register(). */\r\n registerTool: (tool: unknown) => void;\r\n /**\r\n * The user's config values for this plugin, keyed by field name.\r\n * Validated against configSchema by OpenClaw before register() is called.\r\n * May be undefined if the user has not configured the plugin.\r\n */\r\n pluginConfig?: Record<string, unknown>;\r\n};\r\n\r\n/**\r\n * The object returned by `createEntry()` — the plugin's public contract.\r\n *\r\n * When using `definePlugin`, this is constructed automatically.\r\n * Exported for advanced plugins that build it manually.\r\n */\r\nexport interface PluginEntry {\r\n /** Unique plugin id. Used as the CLI binary name and OpenClaw config key. */\r\n id: string;\r\n /** Human-readable display name. */\r\n name: string;\r\n /** One-sentence description. */\r\n description?: string;\r\n /** Tool names this plugin promises to register. Derived automatically by `definePlugin`. */\r\n contracts?: { tools: string[] };\r\n /** When to load the plugin. Defaults to `{ onStartup: true }`. */\r\n activation?: { onStartup?: boolean };\r\n /**\r\n * JSON Schema for the plugin's config block.\r\n * Pass a TypeBox `Type.Object(...)` — it is valid JSON Schema and gives you type inference.\r\n */\r\n configSchema?: unknown;\r\n /** Called once by OpenClaw at startup. Use `definePlugin` instead of implementing this directly. */\r\n register(api: PluginApi): void;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helpers\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Wrap a value in the standard OpenClaw tool result format.\r\n *\r\n * When using `definePlugin`, you do NOT call this yourself — the SDK calls it\r\n * automatically after your `execute` function returns.\r\n *\r\n * For advanced plugins that implement `register()` directly, wrap your\r\n * execute return values with this function.\r\n *\r\n * @param data - Anything JSON-serialisable, or a plain string.\r\n * @returns `{ content: [{ type: \"text\", text: \"<json>\" }], details: {} }`\r\n */\r\nexport function formatResult(data: unknown) {\r\n let text: string;\r\n if (typeof data === \"string\") {\r\n text = data;\r\n } else {\r\n try {\r\n text = JSON.stringify(data) ?? String(data);\r\n } catch {\r\n text = String(data);\r\n }\r\n }\r\n return {\r\n content: [{ type: \"text\" as const, text }],\r\n details: {},\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Adapter factory\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Create the plugin's OpenClaw adapter export.\r\n *\r\n * **You never call this yourself.** It is called by the generated `dist/adapter.js`.\r\n *\r\n * Attempts to load the optional `openclaw` peer dependency and wrap the plugin\r\n * entry with the host's `definePluginEntry()`. Falls back to the raw entry if\r\n * `openclaw` is not installed (standalone CLI mode).\r\n *\r\n * @param entry - The object returned by `createEntry()`.\r\n * @param callerUrl - Pass `import.meta.url` from the generated adapter file.\r\n */\r\nexport function createAdapter(entry: PluginEntry, callerUrl: string): unknown {\r\n const req = createRequire(callerUrl);\r\n\r\n try {\r\n const sdk = req(\"openclaw/plugin-sdk/plugin-entry\") as {\r\n definePluginEntry?: (e: unknown) => unknown;\r\n };\r\n\r\n if (typeof sdk.definePluginEntry !== \"function\") {\r\n throw new Error(\r\n \"OpenClaw SDK loaded but did not export `definePluginEntry`. Upgrade the `openclaw` package.\",\r\n );\r\n }\r\n\r\n return sdk.definePluginEntry(entry);\r\n } catch (err: unknown) {\r\n if (isModuleNotFoundError(err)) return entry;\r\n throw err;\r\n }\r\n}\r\n\r\nfunction isModuleNotFoundError(err: unknown): boolean {\r\n if (!(err instanceof Error)) return false;\r\n return (\r\n \"code\" in err &&\r\n ((err as { code: string }).code === \"MODULE_NOT_FOUND\" ||\r\n (err as { code: string }).code === \"ERR_MODULE_NOT_FOUND\")\r\n );\r\n}\r\n"],"mappings":";AAeA,SAAS,qBAAqB;AAqFvB,SAAS,aAAsD,KAyBhD;AACpB,SAAO,MAAM;AAEX,UAAM,eAAe,CAAC,YAAqB;AAC3C,UAAM,WAAW,IAAI,MAAM,WAAW;AAEtC,WAAO;AAAA,MACL,IAAI,IAAI;AAAA,MACR,MAAM,IAAI;AAAA,MACV,aAAa,IAAI;AAAA,MACjB,YAAY,IAAI,cAAc,EAAE,WAAW,KAAK;AAAA;AAAA,MAEhD,WAAW,EAAE,OAAO,SAAS,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE;AAAA;AAAA,MAEhD,cAAc,IAAI;AAAA,MAClB,SAAS,KAAgB;AAGvB,cAAM,SAAU,IAAI,gBAAgB,CAAC;AAErC,mBAAW,WAAW,UAAU;AAC9B,cAAI,aAAa;AAAA,YACf,MAAM,QAAQ;AAAA,YACd,OAAO,QAAQ,SAAS,QAAQ;AAAA,YAChC,aAAa,QAAQ;AAAA,YACrB,YAAY,QAAQ;AAAA;AAAA,YAEpB,SAAS,OAAO,aAAqB,WACnC,aAAa,MAAM,QAAQ,QAAQ,QAAQ,MAAM,CAAC;AAAA,UACtD,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAoEO,SAAS,aAAa,MAAe;AAC1C,MAAI;AACJ,MAAI,OAAO,SAAS,UAAU;AAC5B,WAAO;AAAA,EACT,OAAO;AACL,QAAI;AACF,aAAO,KAAK,UAAU,IAAI,KAAK,OAAO,IAAI;AAAA,IAC5C,QAAQ;AACN,aAAO,OAAO,IAAI;AAAA,IACpB;AAAA,EACF;AACA,SAAO;AAAA,IACL,SAAS,CAAC,EAAE,MAAM,QAAiB,KAAK,CAAC;AAAA,IACzC,SAAS,CAAC;AAAA,EACZ;AACF;AAkBO,SAAS,cAAc,OAAoB,WAA4B;AAC5E,QAAM,MAAM,cAAc,SAAS;AAEnC,MAAI;AACF,UAAM,MAAM,IAAI,kCAAkC;AAIlD,QAAI,OAAO,IAAI,sBAAsB,YAAY;AAC/C,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,WAAO,IAAI,kBAAkB,KAAK;AAAA,EACpC,SAAS,KAAc;AACrB,QAAI,sBAAsB,GAAG,EAAG,QAAO;AACvC,UAAM;AAAA,EACR;AACF;AAEA,SAAS,sBAAsB,KAAuB;AACpD,MAAI,EAAE,eAAe,OAAQ,QAAO;AACpC,SACE,UAAU,QACR,IAAyB,SAAS,sBACjC,IAAyB,SAAS;AAEzC;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * carapace-plugin-sdk — Core types and helpers for OpenClaw plugins.\n *\n * This is the main entry point. Import `definePlugin` to author a plugin\n * with full TypeScript inference — typed config and typed tool parameters\n * with no boilerplate.\n *\n * Quick-start:\n *\n * src/plugin.ts — the only file you write; export `createEntry` from `definePlugin`\n * dist/adapter.js — auto-generated at build time; do not write by hand\n *\n * @module carapace-plugin-sdk\n */\n\nimport { createRequire } from \"node:module\";\nimport { type TObject, type Static } from \"@sinclair/typebox\";\n\n// ---------------------------------------------------------------------------\n// definePlugin — the primary authoring API\n// ---------------------------------------------------------------------------\n\n/**\n * Internal (erased) tool definition stored at runtime.\n * The typed version lives only in TypeScript's type system via ToolFactory<TConfig>.\n */\ninterface ToolDef {\n name: string;\n label?: string;\n description: string;\n parameters: unknown;\n execute(params: Record<string, unknown>, config: unknown): Promise<unknown>;\n}\n\n/**\n * Typed tool factory injected into the `tools` callback of `definePlugin`.\n *\n * TConfig is fixed by the enclosing `definePlugin` call, so every tool in the\n * array receives the same config type. TSchema is inferred per tool from the\n * `parameters` field, giving typed `params` in `execute`.\n *\n * You never construct this directly — it is passed to you by `definePlugin`.\n */\ntype ToolFactory<TConfig> = <TSchema extends TObject>(def: {\n /** Machine-readable name, used as the CLI subcommand. snake_case recommended. */\n name: string;\n /** Human-readable label shown in OpenClaw's UI. Defaults to `name`. */\n label?: string;\n /** One-sentence description shown in --help and OpenClaw's tool inspector. */\n description: string;\n /**\n * TypeBox schema for the tool's parameters.\n * The type is inferred as `Static<TSchema>` in `execute`'s first argument.\n */\n parameters: TSchema;\n /**\n * The tool's implementation.\n *\n * @param params - Typed parameters derived from `parameters` schema. No casts needed.\n * @param config - Typed config derived from `definePlugin`'s `configSchema`. No casts needed.\n * @returns Any JSON-serialisable value. The SDK wraps it in the OpenClaw result format.\n */\n execute(params: Static<TSchema>, config: TConfig): Promise<unknown>;\n}) => ToolDef;\n\n/**\n * Define an OpenClaw plugin with full TypeScript inference.\n *\n * Returns a `createEntry` function — export it from your `src/index.ts`.\n * The SDK handles all registration, result wrapping, and config plumbing.\n *\n * Config type is inferred from `configSchema` and flows into every tool's\n * `execute(params, config)` without any manual type annotations.\n *\n * @example\n * // src/index.ts — the entire plugin\n * import { definePlugin } from \"carapace-plugin-sdk\";\n * import { Type } from \"@sinclair/typebox\";\n *\n * export const createEntry = definePlugin({\n * id: \"my-plugin\",\n * name: \"My Plugin\",\n * configSchema: Type.Object({\n * apiKey: Type.Optional(Type.String({ description: \"API key.\" })),\n * }),\n * tools: (tool) => [\n * tool({\n * name: \"do_thing\",\n * description: \"Does the thing.\",\n * parameters: Type.Object({\n * input: Type.String({ description: \"Input value.\" }),\n * }),\n * execute: async ({ input }, config) => {\n * // input: string ✓ config.apiKey: string | undefined ✓\n * return { result: input };\n * },\n * }),\n * ],\n * });\n */\nexport function definePlugin<TConfigSchema extends TObject = TObject>(def: {\n /** Unique plugin id. Lowercase alphanumeric with hyphens. Used as the CLI binary name. */\n id: string;\n /** Human-readable display name. */\n name: string;\n /** One-sentence description of what the plugin does. */\n description?: string;\n /** When to load the plugin. Defaults to `{ onStartup: true }`. */\n activation?: { onStartup?: boolean };\n /**\n * TypeBox schema for the plugin's config block.\n *\n * Used for three things simultaneously:\n * 1. Runtime JSON Schema for the OpenClaw manifest (validated before register())\n * 2. TypeScript type inference for `config` in every tool's `execute`\n * 3. Environment variable mapping for the standalone CLI\n */\n configSchema?: TConfigSchema;\n /**\n * Declare your tools here. Receives a typed `tool()` factory as its argument.\n *\n * Using a callback (rather than a plain array) is what allows TypeScript to\n * thread the config type through to each tool's `execute` function.\n */\n tools: (tool: ToolFactory<Static<TConfigSchema>>) => ToolDef[];\n}): () => PluginEntry {\n return () => {\n // The factory is identity at runtime — all type magic is compile-time only.\n const toolFactory = ((toolDef: unknown) => toolDef) as ToolFactory<Static<TConfigSchema>>;\n const toolDefs = def.tools(toolFactory);\n\n return {\n id: def.id,\n name: def.name,\n description: def.description,\n activation: def.activation ?? { onStartup: true },\n // Derive contracts from the declared tools so the manifest is always accurate.\n contracts: { tools: toolDefs.map((t) => t.name) },\n // TypeBox TObject is valid JSON Schema — pass through for the manifest generator.\n configSchema: def.configSchema as unknown as PluginEntry[\"configSchema\"],\n register(api: PluginApi) {\n // OpenClaw validates pluginConfig against configSchema before calling register(),\n // so this cast is safe. Fall back to empty object if config is not yet set.\n const config = (api.pluginConfig ?? {}) as Static<TConfigSchema>;\n\n for (const toolDef of toolDefs) {\n api.registerTool({\n name: toolDef.name,\n label: toolDef.label ?? toolDef.name,\n description: toolDef.description,\n parameters: toolDef.parameters,\n // Wrap the result automatically — execute() returns plain values, not formatResult().\n execute: async (_toolCallId: string, params: Record<string, unknown>) =>\n formatResult(await toolDef.execute(params, config)),\n });\n }\n },\n };\n };\n}\n\n// ---------------------------------------------------------------------------\n// Low-level types — the plugin contract\n//\n// These are used by the generated adapter and by advanced plugins that need\n// more control than definePlugin provides (e.g. dynamic tool registration).\n// ---------------------------------------------------------------------------\n\n/**\n * The API object passed to your plugin's `register()` function.\n *\n * When using `definePlugin`, you never see this directly — the SDK handles it.\n * It is exported for advanced use cases and for the generated adapter.\n */\nexport type PluginApi = {\n /** Register a tool with OpenClaw. Call once per tool inside register(). */\n registerTool: (tool: unknown) => void;\n /**\n * The user's config values for this plugin, keyed by field name.\n * Validated against configSchema by OpenClaw before register() is called.\n * May be undefined if the user has not configured the plugin.\n */\n pluginConfig?: Record<string, unknown>;\n};\n\n/**\n * The object returned by `createEntry()` — the plugin's public contract.\n *\n * When using `definePlugin`, this is constructed automatically.\n * Exported for advanced plugins that build it manually.\n */\nexport interface PluginEntry {\n /** Unique plugin id. Used as the CLI binary name and OpenClaw config key. */\n id: string;\n /** Human-readable display name. */\n name: string;\n /** One-sentence description. */\n description?: string;\n /** Tool names this plugin promises to register. Derived automatically by `definePlugin`. */\n contracts?: { tools: string[] };\n /** When to load the plugin. Defaults to `{ onStartup: true }`. */\n activation?: { onStartup?: boolean };\n /**\n * JSON Schema for the plugin's config block.\n * Pass a TypeBox `Type.Object(...)` — it is valid JSON Schema and gives you type inference.\n */\n configSchema?: unknown;\n /** Called once by OpenClaw at startup. Use `definePlugin` instead of implementing this directly. */\n register(api: PluginApi): void;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Wrap a value in the standard OpenClaw tool result format.\n *\n * When using `definePlugin`, you do NOT call this yourself — the SDK calls it\n * automatically after your `execute` function returns.\n *\n * For advanced plugins that implement `register()` directly, wrap your\n * execute return values with this function.\n *\n * @param data - Anything JSON-serialisable, or a plain string.\n * @returns `{ content: [{ type: \"text\", text: \"<json>\" }], details: {} }`\n */\nexport function formatResult(data: unknown) {\n let text: string;\n if (typeof data === \"string\") {\n text = data;\n } else {\n try {\n text = JSON.stringify(data) ?? String(data);\n } catch {\n text = String(data);\n }\n }\n return {\n content: [{ type: \"text\" as const, text }],\n details: {},\n };\n}\n\n// ---------------------------------------------------------------------------\n// Adapter factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create the plugin's OpenClaw adapter export.\n *\n * **You never call this yourself.** It is called by the generated `dist/adapter.js`.\n *\n * Attempts to load the optional `openclaw` peer dependency and wrap the plugin\n * entry with the host's `definePluginEntry()`. Falls back to the raw entry if\n * `openclaw` is not installed (standalone CLI mode).\n *\n * @param entry - The object returned by `createEntry()`.\n * @param callerUrl - Pass `import.meta.url` from the generated adapter file.\n */\nexport function createAdapter(entry: PluginEntry, callerUrl: string): unknown {\n const req = createRequire(callerUrl);\n\n try {\n const sdk = req(\"openclaw/plugin-sdk/plugin-entry\") as {\n definePluginEntry?: (e: unknown) => unknown;\n };\n\n if (typeof sdk.definePluginEntry !== \"function\") {\n throw new Error(\n \"OpenClaw SDK loaded but did not export `definePluginEntry`. Upgrade the `openclaw` package.\",\n );\n }\n\n return sdk.definePluginEntry(entry);\n } catch (err: unknown) {\n if (isModuleNotFoundError(err)) return entry;\n throw err;\n }\n}\n\nfunction isModuleNotFoundError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n return (\n \"code\" in err &&\n ((err as { code: string }).code === \"MODULE_NOT_FOUND\" ||\n (err as { code: string }).code === \"ERR_MODULE_NOT_FOUND\")\n );\n}\n"],"mappings":";AAeA,SAAS,qBAAqB;AAqFvB,SAAS,aAAsD,KAyBhD;AACpB,SAAO,MAAM;AAEX,UAAM,eAAe,CAAC,YAAqB;AAC3C,UAAM,WAAW,IAAI,MAAM,WAAW;AAEtC,WAAO;AAAA,MACL,IAAI,IAAI;AAAA,MACR,MAAM,IAAI;AAAA,MACV,aAAa,IAAI;AAAA,MACjB,YAAY,IAAI,cAAc,EAAE,WAAW,KAAK;AAAA;AAAA,MAEhD,WAAW,EAAE,OAAO,SAAS,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE;AAAA;AAAA,MAEhD,cAAc,IAAI;AAAA,MAClB,SAAS,KAAgB;AAGvB,cAAM,SAAU,IAAI,gBAAgB,CAAC;AAErC,mBAAW,WAAW,UAAU;AAC9B,cAAI,aAAa;AAAA,YACf,MAAM,QAAQ;AAAA,YACd,OAAO,QAAQ,SAAS,QAAQ;AAAA,YAChC,aAAa,QAAQ;AAAA,YACrB,YAAY,QAAQ;AAAA;AAAA,YAEpB,SAAS,OAAO,aAAqB,WACnC,aAAa,MAAM,QAAQ,QAAQ,QAAQ,MAAM,CAAC;AAAA,UACtD,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAoEO,SAAS,aAAa,MAAe;AAC1C,MAAI;AACJ,MAAI,OAAO,SAAS,UAAU;AAC5B,WAAO;AAAA,EACT,OAAO;AACL,QAAI;AACF,aAAO,KAAK,UAAU,IAAI,KAAK,OAAO,IAAI;AAAA,IAC5C,QAAQ;AACN,aAAO,OAAO,IAAI;AAAA,IACpB;AAAA,EACF;AACA,SAAO;AAAA,IACL,SAAS,CAAC,EAAE,MAAM,QAAiB,KAAK,CAAC;AAAA,IACzC,SAAS,CAAC;AAAA,EACZ;AACF;AAkBO,SAAS,cAAc,OAAoB,WAA4B;AAC5E,QAAM,MAAM,cAAc,SAAS;AAEnC,MAAI;AACF,UAAM,MAAM,IAAI,kCAAkC;AAIlD,QAAI,OAAO,IAAI,sBAAsB,YAAY;AAC/C,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,WAAO,IAAI,kBAAkB,KAAK;AAAA,EACpC,SAAS,KAAc;AACrB,QAAI,sBAAsB,GAAG,EAAG,QAAO;AACvC,UAAM;AAAA,EACR;AACF;AAEA,SAAS,sBAAsB,KAAuB;AACpD,MAAI,EAAE,eAAe,OAAQ,QAAO;AACpC,SACE,UAAU,QACR,IAAyB,SAAS,sBACjC,IAAyB,SAAS;AAEzC;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,54 +1,58 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "carapace-plugin-sdk",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "🦞🐚 SDK for building OpenClaw plugins — types, helpers, CLI generation",
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
"
|
|
12
|
-
"types": "./dist/
|
|
13
|
-
"import": "./dist/
|
|
14
|
-
},
|
|
15
|
-
"./
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
"
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "carapace-plugin-sdk",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "🦞🐚 SDK for building OpenClaw plugins — types, helpers, CLI generation",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/JeffSteinbok/carapace-plugin-sdk"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./cli": {
|
|
16
|
+
"types": "./dist/cli.d.ts",
|
|
17
|
+
"import": "./dist/cli.js"
|
|
18
|
+
},
|
|
19
|
+
"./tsup": {
|
|
20
|
+
"import": "./dist/tsup.plugin.config.js"
|
|
21
|
+
},
|
|
22
|
+
"./tsconfig.base.json": "./tsconfig.base.json"
|
|
23
|
+
},
|
|
24
|
+
"bin": {
|
|
25
|
+
"carapace-generate-cli": "./dist/generate-cli.js"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsup",
|
|
29
|
+
"prepare": "tsup",
|
|
30
|
+
"test": "vitest run"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist",
|
|
34
|
+
"tsconfig.base.json",
|
|
35
|
+
"README.md",
|
|
36
|
+
"LICENSE"
|
|
37
|
+
],
|
|
38
|
+
"keywords": [
|
|
39
|
+
"openclaw",
|
|
40
|
+
"plugin",
|
|
41
|
+
"sdk",
|
|
42
|
+
"carapace",
|
|
43
|
+
"cli"
|
|
44
|
+
],
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/node": "^22",
|
|
48
|
+
"tsup": "^8.3.0",
|
|
49
|
+
"typescript": "^5.7",
|
|
50
|
+
"vitest": "^2.1.8"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=20"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"@sinclair/typebox": "^0.34.0"
|
|
57
|
+
}
|
|
58
|
+
}
|