@every-env/compound-plugin 0.5.0 → 0.5.2
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/package.json +1 -1
- package/src/commands/install.ts +16 -9
- package/tests/cli.test.ts +62 -0
package/package.json
CHANGED
package/src/commands/install.ts
CHANGED
|
@@ -88,7 +88,8 @@ export default defineCommand({
|
|
|
88
88
|
if (!bundle) {
|
|
89
89
|
throw new Error(`Target ${targetName} did not return a bundle.`)
|
|
90
90
|
}
|
|
91
|
-
const
|
|
91
|
+
const hasExplicitOutput = Boolean(args.output && String(args.output).trim())
|
|
92
|
+
const primaryOutputRoot = resolveTargetOutputRoot(targetName, outputRoot, codexHome, hasExplicitOutput)
|
|
92
93
|
await target.write(primaryOutputRoot, bundle)
|
|
93
94
|
console.log(`Installed ${plugin.manifest.name} to ${primaryOutputRoot}`)
|
|
94
95
|
|
|
@@ -109,7 +110,7 @@ export default defineCommand({
|
|
|
109
110
|
console.warn(`Skipping ${extra}: no output returned.`)
|
|
110
111
|
continue
|
|
111
112
|
}
|
|
112
|
-
const extraRoot = resolveTargetOutputRoot(extra, path.join(outputRoot, extra), codexHome)
|
|
113
|
+
const extraRoot = resolveTargetOutputRoot(extra, path.join(outputRoot, extra), codexHome, hasExplicitOutput)
|
|
113
114
|
await handler.write(extraRoot, extraBundle)
|
|
114
115
|
console.log(`Installed ${plugin.manifest.name} to ${extraRoot}`)
|
|
115
116
|
}
|
|
@@ -131,12 +132,15 @@ type ResolvedPluginPath = {
|
|
|
131
132
|
}
|
|
132
133
|
|
|
133
134
|
async function resolvePluginPath(input: string): Promise<ResolvedPluginPath> {
|
|
134
|
-
|
|
135
|
-
if (
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
135
|
+
// Only treat as a local path if it explicitly looks like one
|
|
136
|
+
if (input.startsWith(".") || input.startsWith("/") || input.startsWith("~")) {
|
|
137
|
+
const expanded = expandHome(input)
|
|
138
|
+
const directPath = path.resolve(expanded)
|
|
139
|
+
if (await pathExists(directPath)) return { path: directPath }
|
|
140
|
+
throw new Error(`Local plugin path not found: ${directPath}`)
|
|
141
|
+
}
|
|
139
142
|
|
|
143
|
+
// Otherwise, always fetch the latest from GitHub
|
|
140
144
|
return await resolveGitHubPluginPath(input)
|
|
141
145
|
}
|
|
142
146
|
|
|
@@ -178,10 +182,13 @@ function resolveOutputRoot(value: unknown): string {
|
|
|
178
182
|
return path.join(os.homedir(), ".config", "opencode")
|
|
179
183
|
}
|
|
180
184
|
|
|
181
|
-
function resolveTargetOutputRoot(targetName: string, outputRoot: string, codexHome: string): string {
|
|
185
|
+
function resolveTargetOutputRoot(targetName: string, outputRoot: string, codexHome: string, hasExplicitOutput: boolean): string {
|
|
182
186
|
if (targetName === "codex") return codexHome
|
|
183
187
|
if (targetName === "droid") return path.join(os.homedir(), ".factory")
|
|
184
|
-
if (targetName === "cursor")
|
|
188
|
+
if (targetName === "cursor") {
|
|
189
|
+
const base = hasExplicitOutput ? outputRoot : process.cwd()
|
|
190
|
+
return path.join(base, ".cursor")
|
|
191
|
+
}
|
|
185
192
|
return outputRoot
|
|
186
193
|
}
|
|
187
194
|
|
package/tests/cli.test.ts
CHANGED
|
@@ -180,6 +180,68 @@ describe("CLI", () => {
|
|
|
180
180
|
expect(await exists(path.join(tempRoot, ".config", "opencode", "agents", "repo-research-analyst.md"))).toBe(true)
|
|
181
181
|
})
|
|
182
182
|
|
|
183
|
+
test("install by name ignores same-named local directory", async () => {
|
|
184
|
+
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "cli-shadow-"))
|
|
185
|
+
const workspaceRoot = await fs.mkdtemp(path.join(os.tmpdir(), "cli-shadow-workspace-"))
|
|
186
|
+
const repoRoot = await fs.mkdtemp(path.join(os.tmpdir(), "cli-shadow-repo-"))
|
|
187
|
+
|
|
188
|
+
// Create a directory with the plugin name that is NOT a valid plugin
|
|
189
|
+
const shadowDir = path.join(workspaceRoot, "compound-engineering")
|
|
190
|
+
await fs.mkdir(shadowDir, { recursive: true })
|
|
191
|
+
await fs.writeFile(path.join(shadowDir, "README.md"), "Not a plugin")
|
|
192
|
+
|
|
193
|
+
// Set up a fake GitHub source with a valid plugin
|
|
194
|
+
const fixtureRoot = path.join(import.meta.dir, "fixtures", "sample-plugin")
|
|
195
|
+
const pluginRoot = path.join(repoRoot, "plugins", "compound-engineering")
|
|
196
|
+
await fs.mkdir(path.dirname(pluginRoot), { recursive: true })
|
|
197
|
+
await fs.cp(fixtureRoot, pluginRoot, { recursive: true })
|
|
198
|
+
|
|
199
|
+
const gitEnv = {
|
|
200
|
+
...process.env,
|
|
201
|
+
GIT_AUTHOR_NAME: "Test",
|
|
202
|
+
GIT_AUTHOR_EMAIL: "test@example.com",
|
|
203
|
+
GIT_COMMITTER_NAME: "Test",
|
|
204
|
+
GIT_COMMITTER_EMAIL: "test@example.com",
|
|
205
|
+
}
|
|
206
|
+
await runGit(["init"], repoRoot, gitEnv)
|
|
207
|
+
await runGit(["add", "."], repoRoot, gitEnv)
|
|
208
|
+
await runGit(["commit", "-m", "fixture"], repoRoot, gitEnv)
|
|
209
|
+
|
|
210
|
+
const projectRoot = path.join(import.meta.dir, "..")
|
|
211
|
+
const proc = Bun.spawn([
|
|
212
|
+
"bun",
|
|
213
|
+
"run",
|
|
214
|
+
path.join(projectRoot, "src", "index.ts"),
|
|
215
|
+
"install",
|
|
216
|
+
"compound-engineering",
|
|
217
|
+
"--to",
|
|
218
|
+
"opencode",
|
|
219
|
+
"--output",
|
|
220
|
+
tempRoot,
|
|
221
|
+
], {
|
|
222
|
+
cwd: workspaceRoot,
|
|
223
|
+
stdout: "pipe",
|
|
224
|
+
stderr: "pipe",
|
|
225
|
+
env: {
|
|
226
|
+
...process.env,
|
|
227
|
+
HOME: tempRoot,
|
|
228
|
+
COMPOUND_PLUGIN_GITHUB_SOURCE: repoRoot,
|
|
229
|
+
},
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
const exitCode = await proc.exited
|
|
233
|
+
const stdout = await new Response(proc.stdout).text()
|
|
234
|
+
const stderr = await new Response(proc.stderr).text()
|
|
235
|
+
|
|
236
|
+
if (exitCode !== 0) {
|
|
237
|
+
throw new Error(`CLI failed (exit ${exitCode}).\nstdout: ${stdout}\nstderr: ${stderr}`)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Should succeed by fetching from GitHub, NOT failing on the local shadow directory
|
|
241
|
+
expect(stdout).toContain("Installed compound-engineering")
|
|
242
|
+
expect(await exists(path.join(tempRoot, "opencode.json"))).toBe(true)
|
|
243
|
+
})
|
|
244
|
+
|
|
183
245
|
test("convert writes OpenCode output", async () => {
|
|
184
246
|
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "cli-convert-"))
|
|
185
247
|
const fixtureRoot = path.join(import.meta.dir, "fixtures", "sample-plugin")
|