harness-alchemist 0.1.8 → 0.1.10

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 (40) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/README.md +25 -14
  4. package/alchemy.json +8 -0
  5. package/alchemy.schema.json +1 -1
  6. package/dist/deepseek.d.ts +2 -2
  7. package/dist/deepseek.d.ts.map +1 -1
  8. package/dist/deepseek.js +7 -20
  9. package/dist/deepseek.js.map +1 -1
  10. package/dist/opencode.d.ts +2 -19
  11. package/dist/opencode.d.ts.map +1 -1
  12. package/dist/opencode.js +5 -53
  13. package/dist/opencode.js.map +1 -1
  14. package/lib/create.mjs +2 -0
  15. package/lib/validate.mjs +86 -12
  16. package/mcp.json +19 -0
  17. package/package.json +6 -1
  18. package/plugin.json +16 -2
  19. package/skills/harness-alchemist/SKILL.md +5 -5
  20. package/skills/harness-alchemist/references/antigravity.md +2 -2
  21. package/skills/harness-alchemist/references/compatibility.md +10 -8
  22. package/skills/harness-alchemist/references/deepseek-harness.md +5 -3
  23. package/skills/harness-alchemist/references/publishing.md +12 -10
  24. package/skills/harness-alchemist/skill-runtime.json +50 -0
  25. package/templates/v0.1.0/universal-typescript/.agents/skills/develop-template/SKILL.md.tpl +8 -8
  26. package/templates/v0.1.0/universal-typescript/.agents/skills/develop-template/references/compatibility.md.tpl +12 -12
  27. package/templates/v0.1.0/universal-typescript/.agents/skills/develop-template/scripts/check-package.mjs.tpl +3 -0
  28. package/templates/v0.1.0/universal-typescript/.agents/skills/develop-template/scripts/sync-metadata.mjs.tpl +12 -4
  29. package/templates/v0.1.0/universal-typescript/.github/workflows/npm-publish.yml.tpl +39 -20
  30. package/templates/v0.1.0/universal-typescript/AGENTS.md.tpl +4 -2
  31. package/templates/v0.1.0/universal-typescript/README.md.tpl +13 -9
  32. package/templates/v0.1.0/universal-typescript/mcp.json.tpl +19 -0
  33. package/templates/v0.1.0/universal-typescript/package.json.tpl +4 -0
  34. package/templates/v0.1.0/universal-typescript/plugin.json.tpl +10 -2
  35. package/templates/v0.1.0/universal-typescript/skills/shared-skill/SKILL.md.tpl +4 -3
  36. package/templates/v0.1.0/universal-typescript/skills/shared-skill/references/tool-contract.md.tpl +14 -12
  37. package/templates/v0.1.0/universal-typescript/skills/shared-skill/skill-runtime.json.tpl +50 -0
  38. package/templates/v0.1.0/universal-typescript/src/deepseek.ts.tpl +7 -26
  39. package/templates/v0.1.0/universal-typescript/src/opencode.ts.tpl +6 -59
  40. package/templates/v0.1.0/universal-typescript/tests/runtimes.test.mjs.tpl +44 -9
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "harness-alchemist",
4
4
  "displayName": "Harness Alchemist",
5
- "version": "0.1.8",
5
+ "version": "0.1.10",
6
6
  "description": "Scaffold, validate, and publish portable coding-agent plugins across Claude Code, Codex, OpenCode, Antigravity, and DeepSeek Harness.",
7
7
  "author": {
8
8
  "name": "Haochuan Zhang"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "harness-alchemist",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "Scaffold, validate, and publish portable coding-agent plugins across Claude Code, Codex, OpenCode, Antigravity, and DeepSeek Harness.",
5
5
  "author": {
6
6
  "name": "Haochuan Zhang",
package/README.md CHANGED
@@ -28,7 +28,7 @@
28
28
 
29
29
  ---
30
30
 
31
- Harness Alchemist scaffolds one TypeScript plugin repository that installs natively into **Claude Code**, **Codex/ChatGPT**, **OpenCode**, **Google Antigravity**, and **DeepSeek Harness/Cordis**. Product skills ship behavioral `.mjs`/`.py` script twins; every harness entrypoint is a thin adapter that delegates to them.
31
+ Harness Alchemist scaffolds one TypeScript plugin repository that installs natively into **Claude Code**, **Codex/ChatGPT**, **OpenCode**, **Google Antigravity**, and **DeepSeek Harness/Cordis**. Each product skill declares its fixed executable and portable tool schema in `skill-runtime.json`; host entrypoints delegate through `@lunarmoon26/agent-skill-runtime`.
32
32
 
33
33
  ## Install
34
34
 
@@ -38,7 +38,7 @@ npm install -g harness-alchemist
38
38
  npx harness-alchemist@latest create my-plugin --help
39
39
  ```
40
40
 
41
- Requires Node.js 22.20+ (Bun 1.2+ also supported). Zero runtime dependencies.
41
+ Requires Node.js 22.20+ (Bun 1.2+ also supported).
42
42
 
43
43
  ## Quick start
44
44
 
@@ -78,10 +78,10 @@ retains the strict generated single-package layout.
78
78
 
79
79
  The optional `runtime` field selects what the adapted package must contain:
80
80
 
81
- - `"npm"` (default) — the full generated contract: npm metadata, OpenCode and
82
- Cordis adapters, Cordis patch, and `.mjs`/`.py` script twins.
83
- - `"skills"` — skills and harness manifests only. No npm package, adapters, or
84
- Cordis patch are required, and single-language scripts are allowed, so
81
+ - `"npm"` (default) — the full generated contract: npm metadata, portable
82
+ runtime manifests, OpenCode and Cordis adapters, and the Cordis patch.
83
+ - `"skills"` — skills, portable runtime manifests, and harness manifests only.
84
+ No npm package, adapters, or Cordis patch are required, and single-language scripts are allowed, so
85
85
  Python, Go, Rust, Java, C#, or Swift repositories can expose their workflows
86
86
  to Claude Code, Codex, Antigravity, and DeepSeek's filesystem skill roots
87
87
  without adopting a JavaScript runtime.
@@ -95,10 +95,10 @@ version.
95
95
 
96
96
  | Surface | Purpose |
97
97
  | --- | --- |
98
- | `skills/<name>/` | Agent Skills spec skill with `.mjs`/`.py` script twins under `scripts/` and a tool-contract reference |
99
- | `src/opencode.ts` | OpenCode plugin registering tools that spawn the skill scripts |
100
- | `src/deepseek.ts` + `cordis.patch.yml` | Cordis function plugin providing a service over the same scripts |
101
- | `.claude-plugin/`, `.codex-plugin/`, `.agents/plugins/`, `plugin.json` | Native manifests for Claude Code, Codex, and Antigravity marketplaces |
98
+ | `skills/<name>/` | Agent Skills workflow, portable `skill-runtime.json`, fixed executable, optional tested twin, and tool-contract reference |
99
+ | `src/opencode.ts` | OpenCode plugin projecting the portable runtime manifest as native tools |
100
+ | `src/deepseek.ts` + `cordis.patch.yml` | Cordis function plugin registering the same portable tools |
101
+ | `.claude-plugin/`, `.codex-plugin/`, `.agents/plugins/`, `plugin.json`, `mcp.json` | Native and Agent Plugins manifests for Claude Code, Codex, Antigravity, and MCP hosts |
102
102
  | `.agents/skills/develop-<name>/` | Repository-maintenance skill so agents can develop the project recursively |
103
103
  | `.github/workflows/` | CI plus tag-triggered publish (`vX.Y.Z` → verify → npm provenance) |
104
104
 
@@ -112,12 +112,16 @@ Install paths below are verified against real CLIs before shipping in the templa
112
112
  | Codex/ChatGPT | bundled natively | — | `codex plugin add <name>@<marketplace>` |
113
113
  | OpenCode | via `~/.agents/skills/` | npm package hooks | `"plugin": ["<package>"]` in `opencode.json` |
114
114
  | Google Antigravity | nested bundle | — | `agy plugin validate . && agy plugin install .` |
115
- | DeepSeek Harness | profile filesystem roots | Cordis service plugin | `dsh plugin --profile demo add <package-or-path>` |
115
+ | DeepSeek Harness | profile filesystem roots | Cordis tool plugin | `dsh plugin --profile demo add <package-or-path>` |
116
116
 
117
117
  ## Skill script contract
118
118
 
119
119
  Product skills own their logic; adapters never do.
120
120
 
121
+ `skills/<name>/skill-runtime.json` declares the model-facing schema and selects
122
+ one author-controlled entrypoint. Hosts validate the same manifest and never
123
+ accept an executable path from model input.
124
+
121
125
  ```bash
122
126
  echo '{"request": "hello"}' | node skills/<name>/scripts/main.mjs
123
127
  # {"ok":true,"plugin":"my-plugin","echo":{"request":"hello"}}
@@ -125,7 +129,8 @@ echo '{"request": "hello"}' | node skills/<name>/scripts/main.mjs
125
129
 
126
130
  - One JSON object on stdin, one JSON result plus newline on stdout.
127
131
  - Non-zero exit with a stderr diagnostic on failure.
128
- - `scripts/main.py` is a stdlib-only behavioral twin of `scripts/main.mjs`.
132
+ - `scripts/main.py` is a stdlib-only behavioral twin for direct compatibility
133
+ testing; the starter manifest selects `scripts/main.mjs` for host tools.
129
134
 
130
135
  ## Install-level verification
131
136
 
@@ -152,14 +157,20 @@ and the DeepSeek Cordis check require npm mode with built adapters
152
157
 
153
158
  ## Validation tiers
154
159
 
155
- `npm run validate` always enforces Agent Skills frontmatter compliance, SKILL.md reference resolution, and twin parity. With the optional `pyodide` devDependency installed, Python entrypoints are additionally compiled and smoke-executed inside a WebAssembly CPython sandbox no native Python required.
160
+ `npm run validate` always enforces Agent Skills frontmatter compliance, SKILL.md reference resolution, runtime-manifest validation, fixed contained entrypoints, and npm-mode twin parity. With the optional `pyodide` devDependency installed, Python twins are additionally compiled and smoke-executed inside a WebAssembly CPython sandbox; Pyodide is validation-only, not a version 1 execution engine.
156
161
 
157
162
  ## Release automation
158
163
 
164
+ The npm package trusts GitHub Actions workflow `npm-publish.yml` in
165
+ `lunarmoon26/harness-alchemist`. The workflow uses OIDC instead of an
166
+ `NPM_TOKEN`, requires the tag to match the committed package version, and
167
+ accepts only commits contained in `main`.
168
+
159
169
  ```bash
160
170
  # bump package.json version, then:
161
171
  npm run sync && npm run verify && git commit -am "Release vX.Y.Z" && git push
162
- git tag vX.Y.Z && git push origin vX.Y.Z # publishes automatically
172
+ # after the release commit is merged to main:
173
+ git tag vX.Y.Z && git push origin vX.Y.Z # publishes through npm Trusted Publishing
163
174
  ```
164
175
 
165
176
  ## License
package/alchemy.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "$schema": "https://unpkg.com/harness-alchemist/alchemy.schema.json",
3
+ "runtime": "npm",
4
+ "template": "v0.1.0",
5
+ "generator": "harness-alchemist",
6
+ "generatorVersion": "0.1.10",
7
+ "createdAt": "2026-08-24T00:00:00.000Z"
8
+ }
@@ -13,7 +13,7 @@
13
13
  "runtime": {
14
14
  "enum": ["npm", "skills"],
15
15
  "default": "npm",
16
- "description": "'npm' requires the full generated contract (npm package, OpenCode and Cordis adapters, Cordis patch, .mjs/.py script twins). 'skills' requires skills and harness manifests only and allows single-language scripts."
16
+ "description": "'npm' requires the full generated contract (npm package, portable runtime manifests, OpenCode and Cordis adapters, and Cordis patch). 'skills' requires skills, portable runtime manifests, and harness manifests only and allows single-language scripts."
17
17
  },
18
18
  "pluginRoot": {
19
19
  "type": "string",
@@ -1,5 +1,5 @@
1
1
  import type { Context } from "@deepseek-ai/cordis";
2
2
  export declare const name = "harness-alchemist";
3
- export declare function runSkillScript(script: string, payload: string): unknown;
4
- export declare function apply(context: Context): void;
3
+ export declare const inject: string[];
4
+ export declare function apply(context: Context): Promise<void>;
5
5
  //# sourceMappingURL=deepseek.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"deepseek.d.ts","sourceRoot":"","sources":["../src/deepseek.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAElD,eAAO,MAAM,IAAI,sBAAsB,CAAA;AAQvC,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAcvE;AAED,wBAAgB,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAK5C"}
1
+ {"version":3,"file":"deepseek.d.ts","sourceRoot":"","sources":["../src/deepseek.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD,eAAO,MAAM,IAAI,sBAAsB,CAAA;AACvC,eAAO,MAAM,MAAM,UAAY,CAAA;AAI/B,wBAAsB,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAK3D"}
package/dist/deepseek.js CHANGED
@@ -1,26 +1,13 @@
1
- import { spawnSync } from "node:child_process";
2
1
  import { dirname, join } from "node:path";
3
2
  import { fileURLToPath } from "node:url";
3
+ import { registerDeepSeekTools } from "@lunarmoon26/agent-skill-runtime/deepseek";
4
4
  export const name = "harness-alchemist";
5
- const scriptsDirectory = join(dirname(fileURLToPath(import.meta.url)), "..", "skills/harness-alchemist/scripts");
6
- export function runSkillScript(script, payload) {
7
- const runtime = script.endsWith(".py") ? "python3" : process.execPath;
8
- const result = spawnSync(runtime, [join(scriptsDirectory, script)], {
9
- input: payload,
10
- encoding: "utf8",
11
- });
12
- if (result.error) {
13
- throw new Error(`Could not run ${script} via ${runtime}: ${result.error.message}`);
14
- }
15
- if (result.status !== 0) {
16
- const diagnostic = result.stderr.trim() || `${script} exited with code ${result.status}`;
17
- throw new Error(diagnostic);
18
- }
19
- return JSON.parse(result.stdout);
20
- }
21
- export function apply(context) {
22
- context.provide(name, {
23
- run: (payload, runtime = "node") => runSkillScript(runtime === "python" ? "main.py" : "main.mjs", payload),
5
+ export const inject = ["tools"];
6
+ const pluginRoot = join(dirname(fileURLToPath(import.meta.url)), "..");
7
+ export async function apply(context) {
8
+ await registerDeepSeekTools(context, {
9
+ pluginRoot,
10
+ manifestPaths: ["skills/harness-alchemist/skill-runtime.json"],
24
11
  });
25
12
  }
26
13
  //# sourceMappingURL=deepseek.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"deepseek.js","sourceRoot":"","sources":["../src/deepseek.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAIxC,MAAM,CAAC,MAAM,IAAI,GAAG,mBAAmB,CAAA;AAEvC,MAAM,gBAAgB,GAAG,IAAI,CAC3B,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EACvC,IAAI,EACJ,kCAAkC,CACnC,CAAA;AAED,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,OAAe;IAC5D,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAA;IACrE,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,EAAE;QAClE,KAAK,EAAE,OAAO;QACd,QAAQ,EAAE,MAAM;KACjB,CAAC,CAAA;IACF,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,iBAAiB,MAAM,QAAQ,OAAO,KAAK,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;IACpF,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,qBAAqB,MAAM,CAAC,MAAM,EAAE,CAAA;QACxF,MAAM,IAAI,KAAK,CAAC,UAAU,CAAC,CAAA;IAC7B,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;AAClC,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,OAAgB;IACpC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE;QACpB,GAAG,EAAE,CAAC,OAAe,EAAE,UAA6B,MAAM,EAAE,EAAE,CAC5D,cAAc,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,EAAE,OAAO,CAAC;KACzE,CAAC,CAAA;AACJ,CAAC"}
1
+ {"version":3,"file":"deepseek.js","sourceRoot":"","sources":["../src/deepseek.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAGxC,OAAO,EAAE,qBAAqB,EAAE,MAAM,2CAA2C,CAAA;AAEjF,MAAM,CAAC,MAAM,IAAI,GAAG,mBAAmB,CAAA;AACvC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,OAAO,CAAC,CAAA;AAE/B,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAA;AAEtE,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,OAAgB;IAC1C,MAAM,qBAAqB,CAAC,OAAO,EAAE;QACnC,UAAU;QACV,aAAa,EAAE,CAAC,6CAA6C,CAAC;KAC/D,CAAC,CAAA;AACJ,CAAC"}
@@ -1,21 +1,4 @@
1
- export declare function runSkillScript(script: string, payload: string): Promise<string>;
2
- declare const plugin: () => Promise<{
3
- tool: {
4
- harness_alchemist_run: {
5
- description: string;
6
- args: {
7
- input: import("zod").ZodString;
8
- runtime: import("zod").ZodOptional<import("zod").ZodEnum<{
9
- node: "node";
10
- python: "python";
11
- }>>;
12
- };
13
- execute(args: {
14
- input: string;
15
- runtime?: "node" | "python" | undefined;
16
- }, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
17
- };
18
- };
19
- }>;
1
+ import type { Plugin } from "@opencode-ai/plugin";
2
+ declare const plugin: Plugin;
20
3
  export default plugin;
21
4
  //# sourceMappingURL=opencode.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"opencode.d.ts","sourceRoot":"","sources":["../src/opencode.ts"],"names":[],"mappings":"AAaA,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA0B/E;AAED,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;EAuBO,CAAA;AAEnB,eAAe,MAAM,CAAA"}
1
+ {"version":3,"file":"opencode.d.ts","sourceRoot":"","sources":["../src/opencode.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAKjD,QAAA,MAAM,MAAM,EAAE,MAGZ,CAAA;AAEF,eAAe,MAAM,CAAA"}
package/dist/opencode.js CHANGED
@@ -1,58 +1,10 @@
1
- import { spawn } from "node:child_process";
2
1
  import { dirname, join } from "node:path";
3
2
  import { fileURLToPath } from "node:url";
4
- import { tool } from "@opencode-ai/plugin";
5
- const scriptsDirectory = join(dirname(fileURLToPath(import.meta.url)), "..", "skills/harness-alchemist/scripts");
6
- export function runSkillScript(script, payload) {
7
- return new Promise((resolveResult, rejectResult) => {
8
- const runtime = script.endsWith(".py") ? "python3" : process.execPath;
9
- const child = spawn(runtime, [join(scriptsDirectory, script)], {
10
- stdio: ["pipe", "pipe", "pipe"],
11
- });
12
- let stdout = "";
13
- let stderr = "";
14
- child.stdout.on("data", (chunk) => {
15
- stdout += chunk;
16
- });
17
- child.stderr.on("data", (chunk) => {
18
- stderr += chunk;
19
- });
20
- child.on("error", (error) => {
21
- rejectResult(new Error(`Could not run ${script} via ${runtime}: ${error.message}`));
22
- });
23
- child.on("close", (code) => {
24
- if (code !== 0) {
25
- rejectResult(new Error(stderr.trim() || `${script} exited with code ${code}`));
26
- }
27
- else {
28
- resolveResult(stdout);
29
- }
30
- });
31
- child.stdin.end(payload);
32
- });
33
- }
34
- const plugin = (async () => {
35
- return {
36
- tool: {
37
- harness_alchemist_run: tool({
38
- description: "Run the Harness Alchemist shared-skill workflow. Delegates to skills/harness-alchemist/scripts.",
39
- args: {
40
- input: tool.schema
41
- .string()
42
- .describe("JSON object passed on stdin to the skill entrypoint"),
43
- runtime: tool.schema
44
- .enum(["node", "python"])
45
- .optional()
46
- .describe("Entrypoint runtime; defaults to node"),
47
- },
48
- execute: async (args) => {
49
- const script = args.runtime === "python" ? "main.py" : "main.mjs";
50
- const output = await runSkillScript(script, args.input);
51
- return JSON.stringify(JSON.parse(output));
52
- },
53
- }),
54
- },
55
- };
3
+ import { createOpenCodePlugin } from "@lunarmoon26/agent-skill-runtime/opencode";
4
+ const pluginRoot = join(dirname(fileURLToPath(import.meta.url)), "..");
5
+ const plugin = createOpenCodePlugin({
6
+ pluginRoot,
7
+ manifestPaths: ["skills/harness-alchemist/skill-runtime.json"],
56
8
  });
57
9
  export default plugin;
58
10
  //# sourceMappingURL=opencode.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"opencode.js","sourceRoot":"","sources":["../src/opencode.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"opencode.js","sourceRoot":"","sources":["../src/opencode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAGxC,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAEhF,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAA;AAEtE,MAAM,MAAM,GAAW,oBAAoB,CAAC;IAC1C,UAAU;IACV,aAAa,EAAE,CAAC,6CAA6C,CAAC;CAC/D,CAAC,CAAA;AAEF,eAAe,MAAM,CAAA"}
package/lib/create.mjs CHANGED
@@ -247,6 +247,8 @@ export async function runCreate(argv) {
247
247
  const tokens = {
248
248
  NAME: options.name,
249
249
  NAME_JSON: JSON.stringify(options.name),
250
+ TOOL_NAME: `${options.name.replaceAll("-", "_")}_run`,
251
+ TOOL_NAME_JSON: JSON.stringify(`${options.name.replaceAll("-", "_")}_run`),
250
252
  DISPLAY_NAME: options.displayName,
251
253
  DISPLAY_NAME_JSON: JSON.stringify(options.displayName),
252
254
  DESCRIPTION: options.description,
package/lib/validate.mjs CHANGED
@@ -2,10 +2,17 @@
2
2
 
3
3
  import { existsSync } from "node:fs"
4
4
  import { readdir, readFile, realpath } from "node:fs/promises"
5
- import { basename, dirname, join, resolve, sep } from "node:path"
5
+ import { basename, dirname, join, relative, resolve, sep } from "node:path"
6
6
  import { fileURLToPath } from "node:url"
7
7
  import { spawnSync } from "node:child_process"
8
8
 
9
+ import { discoverSkillTools } from "@lunarmoon26/agent-skill-runtime"
10
+
11
+ const AGENT_PLUGIN_SCHEMA = "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json"
12
+ const AGENT_PLUGIN_MCP_SCHEMA = "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json"
13
+ const SKILL_RUNTIME_PACKAGE = "@lunarmoon26/agent-skill-runtime"
14
+ const SKILL_RUNTIME_VERSION = "0.1.0"
15
+
9
16
  const PROJECT_REQUIRED_FILES = [
10
17
  ".agents/plugins/marketplace.json",
11
18
  ".claude-plugin/marketplace.json",
@@ -18,6 +25,7 @@ const PROJECT_REQUIRED_FILES = [
18
25
  const PLUGIN_REQUIRED_FILES = [
19
26
  ".claude-plugin/plugin.json",
20
27
  ".codex-plugin/plugin.json",
28
+ "mcp.json",
21
29
  "plugin.json",
22
30
  ]
23
31
 
@@ -38,10 +46,10 @@ Validates a universal Claude, Codex, OpenCode, Antigravity, and DeepSeek
38
46
  plugin scaffold. By default the project is resolved from the current working
39
47
  directory or from the script's containing generated project.
40
48
 
41
- Product skills are checked against the Agent Skills specification and their
42
- scripts against the shared tool contract. When the optional 'pyodide'
43
- devDependency is installed, Python entrypoints are also syntax-checked and
44
- smoke-executed in a WebAssembly CPython sandbox.
49
+ Product skills are checked against the Agent Skills specification and the
50
+ portable skill runtime manifest. When the optional 'pyodide' devDependency is
51
+ installed, Python twin entrypoints are also syntax-checked and smoke-executed
52
+ in a WebAssembly CPython sandbox.
45
53
 
46
54
  Options:
47
55
  --external Run installed platform validators, currently Claude Code.
@@ -245,6 +253,12 @@ function exportTarget(exports, key, field = "import") {
245
253
  return undefined
246
254
  }
247
255
 
256
+ function sameValues(actual, expected) {
257
+ return Array.isArray(actual)
258
+ && actual.length === expected.length
259
+ && expected.every((value, index) => actual[index] === value)
260
+ }
261
+
248
262
  const PYTHON_SMOKE_PROGRAM = `
249
263
  import contextlib
250
264
  import io
@@ -289,7 +303,7 @@ async function smokePythonScripts(scripts, errors, warnings, execSmoke = true) {
289
303
  let output
290
304
  try {
291
305
  if (execSmoke) {
292
- instance.globals.set("__ha_payload__", "{}")
306
+ instance.globals.set("__ha_payload__", '{"request":"validation"}')
293
307
  output = instance.runPython(PYTHON_SMOKE_PROGRAM)
294
308
  } else {
295
309
  instance.runPython('compile(__ha_source__, "<skill>", "exec")\nNone')
@@ -466,7 +480,8 @@ export async function validateProject(projectRoot, options = {}) {
466
480
  join(root, ".agents/plugins/marketplace.json"),
467
481
  errors,
468
482
  )
469
- const antigravityPlugin = await readJson(join(pluginRoot, "plugin.json"), errors)
483
+ const agentPlugin = await readJson(join(pluginRoot, "plugin.json"), errors)
484
+ const agentPluginMcp = await readJson(join(pluginRoot, "mcp.json"), errors)
470
485
 
471
486
  if (errors.length > 0) return { root, errors, warnings }
472
487
 
@@ -482,11 +497,36 @@ export async function validateProject(projectRoot, options = {}) {
482
497
 
483
498
  for (const [label, value] of [
484
499
  ["Codex plugin", codexPlugin.name],
485
- ["Antigravity plugin", antigravityPlugin.name],
500
+ ["Agent plugin", agentPlugin.name],
486
501
  ]) {
487
502
  if (value !== pluginName) errors.push(`${label} name '${value}' does not match '${pluginName}'`)
488
503
  }
489
504
 
505
+ if (agentPlugin.$schema !== AGENT_PLUGIN_SCHEMA) {
506
+ errors.push(`plugin.json $schema must be '${AGENT_PLUGIN_SCHEMA}'`)
507
+ }
508
+ if (agentPluginMcp.$schema !== AGENT_PLUGIN_MCP_SCHEMA) {
509
+ errors.push(`mcp.json $schema must be '${AGENT_PLUGIN_MCP_SCHEMA}'`)
510
+ }
511
+ const expectedMcpArgs = [
512
+ "-y",
513
+ `${SKILL_RUNTIME_PACKAGE}@${SKILL_RUNTIME_VERSION}`,
514
+ "mcp",
515
+ "--root",
516
+ "${PLUGIN_ROOT}",
517
+ "--manifest",
518
+ `skills/${pluginName}/skill-runtime.json`,
519
+ ]
520
+ const mcpServer = agentPluginMcp.mcpServers?.[pluginName]
521
+ if (
522
+ mcpServer?.type !== "stdio" ||
523
+ mcpServer.command !== "npx" ||
524
+ mcpServer.cwd !== "${PLUGIN_ROOT}" ||
525
+ !sameValues(mcpServer.args, expectedMcpArgs)
526
+ ) {
527
+ errors.push(`mcp.json must configure '${pluginName}' through ${SKILL_RUNTIME_PACKAGE}@${SKILL_RUNTIME_VERSION}`)
528
+ }
529
+
490
530
  if (runtime === "skills") {
491
531
  for (const [label, manifest] of [["Codex plugin", codexPlugin]]) {
492
532
  if (manifest.version !== claudePlugin.version) {
@@ -496,8 +536,11 @@ export async function validateProject(projectRoot, options = {}) {
496
536
  errors.push(`${label} description does not match the Claude plugin`)
497
537
  }
498
538
  }
499
- if (antigravityPlugin.description !== claudePlugin.description) {
500
- errors.push("Antigravity description does not match the Claude plugin")
539
+ if (agentPlugin.version !== claudePlugin.version) {
540
+ errors.push("Agent plugin version does not match the Claude plugin")
541
+ }
542
+ if (agentPlugin.description !== claudePlugin.description) {
543
+ errors.push("Agent plugin description does not match the Claude plugin")
501
544
  }
502
545
  } else {
503
546
  const packageJson = await readJson(join(pluginRoot, "package.json"), errors)
@@ -519,11 +562,20 @@ export async function validateProject(projectRoot, options = {}) {
519
562
  errors.push(`${label} description does not match package.json`)
520
563
  }
521
564
  }
522
- if (antigravityPlugin.description !== packageJson.description) {
523
- errors.push("Antigravity description does not match package.json")
565
+ if (agentPlugin.version !== packageJson.version) {
566
+ errors.push("Agent plugin version does not match package.json")
567
+ }
568
+ if (agentPlugin.description !== packageJson.description) {
569
+ errors.push("Agent plugin description does not match package.json")
570
+ }
571
+ if (agentPlugin.license !== packageJson.license) {
572
+ errors.push("Agent plugin license does not match package.json")
524
573
  }
525
574
 
526
575
  if (packageJson.type !== "module") errors.push("package.json type must be 'module'")
576
+ if (packageJson.dependencies?.[SKILL_RUNTIME_PACKAGE] !== SKILL_RUNTIME_VERSION) {
577
+ errors.push(`package.json dependencies must pin '${SKILL_RUNTIME_PACKAGE}' to '${SKILL_RUNTIME_VERSION}'`)
578
+ }
527
579
  if (opencodeExport === "." && packageJson.engines?.node !== ">=22.20.0") {
528
580
  errors.push("package.json engines.node must be '>=22.20.0'")
529
581
  }
@@ -547,6 +599,7 @@ export async function validateProject(projectRoot, options = {}) {
547
599
  "cordis.patch.yml",
548
600
  ".claude-plugin/plugin.json",
549
601
  ".codex-plugin/plugin.json",
602
+ "mcp.json",
550
603
  "plugin.json",
551
604
  ]) {
552
605
  if (!packageJson.files?.includes(entry)) errors.push(`package.json files is missing '${entry}'`)
@@ -599,6 +652,7 @@ export async function validateProject(projectRoot, options = {}) {
599
652
  if (skillFiles.length < 2) errors.push("Expected a shared skill and a project development skill")
600
653
 
601
654
  const pythonScripts = new Set()
655
+ const runtimeManifestPaths = []
602
656
  for (const skillFile of skillFiles) {
603
657
  const content = await readFile(skillFile, "utf8")
604
658
  const frontmatter = parseFrontmatter(content)
@@ -613,11 +667,31 @@ export async function validateProject(projectRoot, options = {}) {
613
667
  errors.push(`${skillFile}: invalid Agent Skill name`)
614
668
  }
615
669
  if (productSkillFiles.includes(skillFile)) {
670
+ const manifestPath = join(dirname(skillFile), "skill-runtime.json")
671
+ if (!existsSync(manifestPath)) {
672
+ errors.push(`${skillFile}: missing skill-runtime.json`)
673
+ } else {
674
+ runtimeManifestPaths.push(relative(pluginRoot, manifestPath))
675
+ }
616
676
  await checkProductSkillRuntime(skillFile, content, frontmatter, errors, pythonScripts, runtime)
617
677
  }
618
678
  }
619
679
  }
620
680
 
681
+ if (runtimeManifestPaths.length === productSkillFiles.length && runtimeManifestPaths.length > 0) {
682
+ try {
683
+ const tools = await discoverSkillTools({ pluginRoot, manifestPaths: runtimeManifestPaths })
684
+ for (const tool of tools) {
685
+ const directoryName = basename(tool.skillRoot)
686
+ if (tool.manifestName !== directoryName) {
687
+ errors.push(`${tool.manifestPath}: manifest name must match skill directory '${directoryName}'`)
688
+ }
689
+ }
690
+ } catch (error) {
691
+ errors.push(`Skill runtime validation failed: ${error instanceof Error ? error.message : String(error)}`)
692
+ }
693
+ }
694
+
621
695
  if (pythonScripts.size > 0) {
622
696
  await smokePythonScripts([...pythonScripts], errors, warnings, runtime === "npm")
623
697
  }
package/mcp.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
3
+ "mcpServers": {
4
+ "harness-alchemist": {
5
+ "type": "stdio",
6
+ "command": "npx",
7
+ "args": [
8
+ "-y",
9
+ "@lunarmoon26/agent-skill-runtime@0.1.0",
10
+ "mcp",
11
+ "--root",
12
+ "${PLUGIN_ROOT}",
13
+ "--manifest",
14
+ "skills/harness-alchemist/skill-runtime.json"
15
+ ],
16
+ "cwd": "${PLUGIN_ROOT}"
17
+ }
18
+ }
19
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "harness-alchemist",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "Scaffold, validate, and publish portable coding-agent plugins across Claude Code, Codex, OpenCode, Antigravity, and DeepSeek Harness.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -25,10 +25,12 @@
25
25
  "lib",
26
26
  "templates",
27
27
  "skills",
28
+ "alchemy.json",
28
29
  "alchemy.schema.json",
29
30
  "cordis.patch.yml",
30
31
  ".claude-plugin/plugin.json",
31
32
  ".codex-plugin/plugin.json",
33
+ "mcp.json",
32
34
  "plugin.json",
33
35
  "README.md",
34
36
  "LICENSE"
@@ -56,6 +58,9 @@
56
58
  "opencode",
57
59
  "scaffolding"
58
60
  ],
61
+ "dependencies": {
62
+ "@lunarmoon26/agent-skill-runtime": "0.1.0"
63
+ },
59
64
  "peerDependencies": {
60
65
  "@deepseek-ai/cordis": "^4.0.1",
61
66
  "@opencode-ai/plugin": "^1.18.21"
package/plugin.json CHANGED
@@ -1,5 +1,19 @@
1
1
  {
2
- "$schema": "https://antigravity.google/schemas/v1/plugin.json",
2
+ "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
3
  "name": "harness-alchemist",
4
- "description": "Scaffold, validate, and publish portable coding-agent plugins across Claude Code, Codex, OpenCode, Antigravity, and DeepSeek Harness."
4
+ "version": "0.1.10",
5
+ "description": "Scaffold, validate, and publish portable coding-agent plugins across Claude Code, Codex, OpenCode, Antigravity, and DeepSeek Harness.",
6
+ "author": {
7
+ "name": "Haochuan Zhang"
8
+ },
9
+ "homepage": "git+https://github.com/lunarmoon26/harness-alchemist.git",
10
+ "repository": "git+https://github.com/lunarmoon26/harness-alchemist.git",
11
+ "license": "MIT",
12
+ "keywords": [
13
+ "agent-skill",
14
+ "scaffolding",
15
+ "mcp",
16
+ "opencode",
17
+ "deepseek"
18
+ ]
5
19
  }
@@ -63,9 +63,9 @@ Static validation is structural evidence, not proof that remote services or host
63
63
 
64
64
  ## Skill Runtime
65
65
 
66
- `scripts/main.mjs` (Node/Bun) and `scripts/main.py` (CPython 3.10+) are
67
- behavioral twins demonstrating this repository's own tool contract: one JSON
68
- object on stdin, one JSON result plus newline on stdout, non-zero exit with a
69
- stderr diagnostic on failure. The `src/` adapters delegate to them; keep any
70
- contract change mirrored in both twins and in
66
+ `skill-runtime.json` declares the fixed `scripts/main.mjs` entrypoint and the
67
+ portable tool schema used by MCP, OpenCode, and DeepSeek. `scripts/main.py`
68
+ (CPython 3.10+) is a direct-test behavioral twin. Both scripts accept one JSON
69
+ object on stdin, return one JSON result plus newline on stdout, and exit non-zero
70
+ with a stderr diagnostic on failure. Keep protocol changes synchronized with
71
71
  [references/compatibility.md](references/compatibility.md).
@@ -4,13 +4,13 @@
4
4
 
5
5
  ```text
6
6
  plugin.json
7
+ mcp.json
7
8
  skills/<name>/SKILL.md
8
9
  rules/<name>.md
9
10
  hooks.json
10
- mcp_config.json
11
11
  ```
12
12
 
13
- Only `plugin.json` is required. The CLI manifest schema accepts a machine-readable name and optional description. Keep the root manifest separate from Claude and Codex manifests.
13
+ `plugin.json` follows Agent Plugins 1.0 and remains separate from the Claude and Codex manifests. `mcp.json` exposes the same executable skill tools to Agent Plugins hosts; current Antigravity CLI releases ignore that file and continue to load the bundled skill.
14
14
 
15
15
  Current Antigravity Agent Skills use the open Agent Skills directory format with nested `<name>/SKILL.md`. This is also the documented plugin skill shape.
16
16