@shenlee/devcrew 0.1.0 → 0.1.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/README.md CHANGED
@@ -34,7 +34,7 @@ Restart Codex, open the plugin directory, choose the DevCrew marketplace, and in
34
34
  The plugin starts the DevCrew MCP server with:
35
35
 
36
36
  ```bash
37
- npx -y @shenlee/devcrew@0.1.0 serve --stdio
37
+ npm exec --silent --yes --package=@shenlee/devcrew@0.1.1 -- node -e "<DevCrew CLI wrapper>" -- serve --stdio
38
38
  ```
39
39
 
40
40
  The plugin locks the MCP server to the published npm package version, so users do not need to clone the source or build TypeScript at install time. You only need Node.js and network access the first time Codex starts the MCP server.
@@ -43,7 +43,6 @@ The plugin locks the MCP server to the published npm package version, so users d
43
43
 
44
44
  ```bash
45
45
  npm install -g @shenlee/devcrew
46
- devcrew --version
47
46
  devcrew doctor /path/to/repo
48
47
  ```
49
48
 
@@ -116,7 +115,7 @@ npm pack --dry-run
116
115
 
117
116
  The SDK adapters use deterministic local fallback output when Codex or Claude SDK packages are not installed. This keeps local tests reliable while preserving the adapter boundary for real host integration. In `apply` mode, DevCrew still inherits the host sandbox and approval boundaries.
118
117
 
119
- For published installs, the host SDK packages are pinned optional dependencies so `npx -y @shenlee/devcrew@<version>` can resolve them from the DevCrew package itself. Plan mode can still fall back to deterministic artifacts, but apply mode fails with a clear SDK resolution error if the selected host SDK is unavailable.
118
+ For published installs, the host SDK packages are pinned optional dependencies so the version-locked `npm exec --package=@shenlee/devcrew@<version>` wrapper can resolve them from the DevCrew package itself. Plan mode can still fall back to deterministic artifacts, but apply mode fails with a clear SDK resolution error if the selected host SDK is unavailable.
120
119
 
121
120
  Public npm publishing is handled by the `npm publish` GitHub Actions workflow. It runs validation, checks the package with `npm pack --dry-run`, and publishes with npm provenance when a GitHub Release is published or the workflow is manually dispatched with `NPM_TOKEN` configured.
122
121
 
package/README.zh-CN.md CHANGED
@@ -34,7 +34,7 @@ codex plugin marketplace add lishen802/devcrew
34
34
  插件会用下面的命令启动 DevCrew MCP 服务:
35
35
 
36
36
  ```bash
37
- npx -y @shenlee/devcrew@0.1.0 serve --stdio
37
+ npm exec --silent --yes --package=@shenlee/devcrew@0.1.1 -- node -e "<DevCrew CLI wrapper>" -- serve --stdio
38
38
  ```
39
39
 
40
40
  插件会锁定到已发布的 npm 包版本,因此用户不需要克隆源码,也不需要在安装时编译 TypeScript;只需要本机有 Node.js,并且 Codex 第一次启动 MCP 服务时可以访问网络。
@@ -43,7 +43,6 @@ npx -y @shenlee/devcrew@0.1.0 serve --stdio
43
43
 
44
44
  ```bash
45
45
  npm install -g @shenlee/devcrew
46
- devcrew --version
47
46
  devcrew doctor /path/to/repo
48
47
  ```
49
48
 
@@ -130,7 +129,7 @@ npm pack --dry-run
130
129
 
131
130
  当前适配器在未安装 Codex SDK 或 Claude SDK 时会使用确定性的本地 fallback 输出。这样可以保证测试和演示稳定,同时保留接入真实宿主 SDK 的边界。即使在 `apply` 模式下,DevCrew 仍然继承宿主的 sandbox、审批和工具权限。
132
131
 
133
- 对于发布安装,宿主 SDK 包会作为精确锁定的 optional dependencies 随 DevCrew 一起安装,因此 `npx -y @shenlee/devcrew@<version>` 可以从 DevCrew 包自身解析这些 SDK。plan 模式仍允许 deterministic fallback;但 apply 模式在选定宿主 SDK 不可用时会直接失败,并给出明确的 SDK 解析错误。
132
+ 对于发布安装,宿主 SDK 包会作为精确锁定的 optional dependencies 随 DevCrew 一起安装,因此锁定版本的 `npm exec --package=@shenlee/devcrew@<version>` wrapper 可以从 DevCrew 包自身解析这些 SDK。plan 模式仍允许 deterministic fallback;但 apply 模式在选定宿主 SDK 不可用时会直接失败,并给出明确的 SDK 解析错误。
134
133
 
135
134
  公开 npm 发布由 `npm publish` GitHub Actions 工作流处理。发布 GitHub Release 或手动触发 workflow 时,它会先运行验证,再执行 `npm pack --dry-run` 检查包内容,最后在配置 `NPM_TOKEN` 后使用 npm provenance 发布公开包。
136
135
 
@@ -1,2 +1,2 @@
1
- export const DEVCREW_VERSION = "0.1.0";
1
+ export const DEVCREW_VERSION = "0.1.1";
2
2
  export const DEVCREW_NPM_PACKAGE = "@shenlee/devcrew";
@@ -63,6 +63,36 @@ function entrySkill() {
63
63
  function npmPackageSpecifier() {
64
64
  return `${DEVCREW_NPM_PACKAGE}@${DEVCREW_VERSION}`;
65
65
  }
66
+ function npmExecCliWrapper() {
67
+ const [scope, name] = DEVCREW_NPM_PACKAGE.split("/");
68
+ return [
69
+ "const path = require('node:path');",
70
+ "const { pathToFileURL } = require('node:url');",
71
+ "const binDir = process.env.PATH.split(path.delimiter)[0];",
72
+ `const packageRoot = path.join(binDir.replace(/[\\\\/]\\.bin$/u, ''), ${JSON.stringify(scope)}, ${JSON.stringify(name)});`,
73
+ "process.argv = ['node', 'devcrew', ...process.argv.slice(1)];",
74
+ "import(pathToFileURL(path.join(packageRoot, 'dist/packages/cli/src/index.js')).href);",
75
+ ].join(" ");
76
+ }
77
+ function mcpServerConfig(host) {
78
+ return {
79
+ command: "npm",
80
+ args: [
81
+ "exec",
82
+ "--silent",
83
+ "--yes",
84
+ `--package=${npmPackageSpecifier()}`,
85
+ "--",
86
+ "node",
87
+ "-e",
88
+ npmExecCliWrapper(),
89
+ "--",
90
+ "serve",
91
+ "--stdio",
92
+ ],
93
+ env: { DEVCREW_HOST: host },
94
+ };
95
+ }
66
96
  export async function generateCodexPlugin(root) {
67
97
  const pluginRoot = join(root, "plugins", "devcrew-codex");
68
98
  await mkdir(join(pluginRoot, ".codex-plugin"), { recursive: true });
@@ -103,11 +133,7 @@ export async function generateCodexPlugin(root) {
103
133
  await writeFile(join(pluginRoot, "skills", "devcrew", "SKILL.md"), entrySkill(), "utf8");
104
134
  await writeJson(join(pluginRoot, ".mcp.json"), {
105
135
  mcpServers: {
106
- devcrew: {
107
- command: "npx",
108
- args: ["-y", npmPackageSpecifier(), "serve", "--stdio"],
109
- env: { DEVCREW_HOST: "codex" },
110
- },
136
+ devcrew: mcpServerConfig("codex"),
111
137
  },
112
138
  });
113
139
  await writeRoleAgents(pluginRoot, "codex");
@@ -151,11 +177,7 @@ export async function generateClaudePlugin(root) {
151
177
  await writeFile(join(pluginRoot, "skills", "devcrew", "SKILL.md"), entrySkill(), "utf8");
152
178
  await writeJson(join(pluginRoot, ".mcp.json"), {
153
179
  mcpServers: {
154
- devcrew: {
155
- command: "npx",
156
- args: ["-y", npmPackageSpecifier(), "serve", "--stdio"],
157
- env: { DEVCREW_HOST: "claude" },
158
- },
180
+ devcrew: mcpServerConfig("claude"),
159
181
  },
160
182
  });
161
183
  await writeRoleAgents(pluginRoot, "claude");
@@ -26,7 +26,7 @@ For local plugin testing:
26
26
  claude --plugin-dir plugins/devcrew-claude
27
27
  ```
28
28
 
29
- Then ask Claude Code to use DevCrew for a feature or product workflow. The generated `.mcp.json` starts the version-locked npm package with `npx -y @shenlee/devcrew@0.1.0 serve --stdio`.
29
+ Then ask Claude Code to use DevCrew for a feature or product workflow. The generated `.mcp.json` starts the version-locked npm package with an `npm exec --package=@shenlee/devcrew@0.1.1` wrapper.
30
30
 
31
31
  Claude Code permissions, hooks, and approval settings remain authoritative. DevCrew inherits the host boundary.
32
32
 
package/docs/codex.md CHANGED
@@ -13,7 +13,7 @@ Restart Codex, open the plugin directory, select the DevCrew marketplace, and in
13
13
  The plugin launches the MCP server with:
14
14
 
15
15
  ```bash
16
- npx -y @shenlee/devcrew@0.1.0 serve --stdio
16
+ npm exec --silent --yes --package=@shenlee/devcrew@0.1.1 -- node -e "<DevCrew CLI wrapper>" -- serve --stdio
17
17
  ```
18
18
 
19
19
  Use this path when you want to use DevCrew without cloning the repository first. The version is locked to the published npm package that matches the plugin manifest.
@@ -37,7 +37,7 @@ devcrew serve --stdio
37
37
  ```
38
38
 
39
39
  Normally the generated plugin starts this command for the host agent.
40
- Codex and Claude plugin bundles use `npx -y @shenlee/devcrew@0.1.0 serve --stdio` so the MCP service is locked to the published package version.
40
+ Codex and Claude plugin bundles use a version-locked `npm exec --package=@shenlee/devcrew@0.1.1` wrapper so the MCP service is locked to the published package version.
41
41
 
42
42
  ## 4. Run A Workflow
43
43
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shenlee/devcrew",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Multi-host agent workflow service for Codex and Claude Code.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -1,2 +1,2 @@
1
- export const DEVCREW_VERSION = "0.1.0";
1
+ export const DEVCREW_VERSION = "0.1.1";
2
2
  export const DEVCREW_NPM_PACKAGE = "@shenlee/devcrew";
@@ -93,6 +93,38 @@ function npmPackageSpecifier(): string {
93
93
  return `${DEVCREW_NPM_PACKAGE}@${DEVCREW_VERSION}`;
94
94
  }
95
95
 
96
+ function npmExecCliWrapper(): string {
97
+ const [scope, name] = DEVCREW_NPM_PACKAGE.split("/");
98
+ return [
99
+ "const path = require('node:path');",
100
+ "const { pathToFileURL } = require('node:url');",
101
+ "const binDir = process.env.PATH.split(path.delimiter)[0];",
102
+ `const packageRoot = path.join(binDir.replace(/[\\\\/]\\.bin$/u, ''), ${JSON.stringify(scope)}, ${JSON.stringify(name)});`,
103
+ "process.argv = ['node', 'devcrew', ...process.argv.slice(1)];",
104
+ "import(pathToFileURL(path.join(packageRoot, 'dist/packages/cli/src/index.js')).href);",
105
+ ].join(" ");
106
+ }
107
+
108
+ function mcpServerConfig(host: "codex" | "claude"): unknown {
109
+ return {
110
+ command: "npm",
111
+ args: [
112
+ "exec",
113
+ "--silent",
114
+ "--yes",
115
+ `--package=${npmPackageSpecifier()}`,
116
+ "--",
117
+ "node",
118
+ "-e",
119
+ npmExecCliWrapper(),
120
+ "--",
121
+ "serve",
122
+ "--stdio",
123
+ ],
124
+ env: { DEVCREW_HOST: host },
125
+ };
126
+ }
127
+
96
128
  export async function generateCodexPlugin(root: string): Promise<GeneratedPlugin> {
97
129
  const pluginRoot = join(root, "plugins", "devcrew-codex");
98
130
  await mkdir(join(pluginRoot, ".codex-plugin"), { recursive: true });
@@ -134,11 +166,7 @@ export async function generateCodexPlugin(root: string): Promise<GeneratedPlugin
134
166
  await writeFile(join(pluginRoot, "skills", "devcrew", "SKILL.md"), entrySkill(), "utf8");
135
167
  await writeJson(join(pluginRoot, ".mcp.json"), {
136
168
  mcpServers: {
137
- devcrew: {
138
- command: "npx",
139
- args: ["-y", npmPackageSpecifier(), "serve", "--stdio"],
140
- env: { DEVCREW_HOST: "codex" },
141
- },
169
+ devcrew: mcpServerConfig("codex"),
142
170
  },
143
171
  });
144
172
  await writeRoleAgents(pluginRoot, "codex");
@@ -184,11 +212,7 @@ export async function generateClaudePlugin(root: string): Promise<GeneratedPlugi
184
212
  await writeFile(join(pluginRoot, "skills", "devcrew", "SKILL.md"), entrySkill(), "utf8");
185
213
  await writeJson(join(pluginRoot, ".mcp.json"), {
186
214
  mcpServers: {
187
- devcrew: {
188
- command: "npx",
189
- args: ["-y", npmPackageSpecifier(), "serve", "--stdio"],
190
- env: { DEVCREW_HOST: "claude" },
191
- },
215
+ devcrew: mcpServerConfig("claude"),
192
216
  },
193
217
  });
194
218
  await writeRoleAgents(pluginRoot, "claude");
@@ -1,10 +1,17 @@
1
1
  {
2
2
  "mcpServers": {
3
3
  "devcrew": {
4
- "command": "npx",
4
+ "command": "npm",
5
5
  "args": [
6
- "-y",
7
- "@shenlee/devcrew@0.1.0",
6
+ "exec",
7
+ "--silent",
8
+ "--yes",
9
+ "--package=@shenlee/devcrew@0.1.1",
10
+ "--",
11
+ "node",
12
+ "-e",
13
+ "const path = require('node:path'); const { pathToFileURL } = require('node:url'); const binDir = process.env.PATH.split(path.delimiter)[0]; const packageRoot = path.join(binDir.replace(/[\\\\/]\\.bin$/u, ''), \"@shenlee\", \"devcrew\"); process.argv = ['node', 'devcrew', ...process.argv.slice(1)]; import(pathToFileURL(path.join(packageRoot, 'dist/packages/cli/src/index.js')).href);",
14
+ "--",
8
15
  "serve",
9
16
  "--stdio"
10
17
  ],
@@ -298,7 +298,7 @@ async function main() {
298
298
  await client.request("initialize", {
299
299
  protocolVersion: "2025-03-26",
300
300
  capabilities: {},
301
- clientInfo: { name: "devcrew-codex-plugin-smoke", version: "0.1.0" },
301
+ clientInfo: { name: "devcrew-codex-plugin-smoke", version: "0.1.1" },
302
302
  });
303
303
  client.notify("notifications/initialized", {});
304
304
  const tools = await client.request("tools/list", {});