compound-workflow 1.4.7 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/.cursor-plugin/plugin.json +4 -4
- package/package.json +3 -1
- package/scripts/check-pack-readme.mjs +16 -1
- package/scripts/check-version-parity.mjs +30 -0
- package/scripts/generate-platform-artifacts.mjs +3 -3
- package/scripts/install-cli.mjs +69 -31
- package/scripts/postinstall.mjs +4 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "compound-workflow",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Clarify -> plan -> execute -> verify -> capture workflow for Cursor",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Compound Workflow"
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
],
|
|
15
15
|
"license": "MIT",
|
|
16
16
|
"repository": "https://github.com/cjerochim/compound-workflow",
|
|
17
|
-
"commands": "src/.agents/commands",
|
|
18
|
-
"agents": "src/.agents/agents",
|
|
19
|
-
"skills": "src/.agents/skills"
|
|
17
|
+
"commands": "./src/.agents/commands",
|
|
18
|
+
"agents": "./src/.agents/agents",
|
|
19
|
+
"skills": "./src/.agents/skills"
|
|
20
20
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "compound-workflow",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Clarify → plan → execute → verify → capture. One Install action for Cursor, Claude, and OpenCode.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"postinstall": "node scripts/postinstall.mjs",
|
|
21
21
|
"generate:artifacts": "node scripts/generate-platform-artifacts.mjs",
|
|
22
22
|
"check:artifacts": "node scripts/generate-platform-artifacts.mjs --check",
|
|
23
|
+
"check:version-parity": "node scripts/check-version-parity.mjs",
|
|
23
24
|
"check:pack-readme": "node scripts/check-pack-readme.mjs",
|
|
24
25
|
"test:install": "node --test tests/install-cli.test.mjs"
|
|
25
26
|
},
|
|
@@ -27,6 +28,7 @@
|
|
|
27
28
|
"node": ">=18"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
31
|
+
"@semantic-release/exec": "^6.0.0",
|
|
30
32
|
"@semantic-release/git": "^10.0.1",
|
|
31
33
|
"@semantic-release/npm": "^13.1.4",
|
|
32
34
|
"semantic-release": "^25.0.3"
|
|
@@ -31,6 +31,9 @@ try {
|
|
|
31
31
|
|
|
32
32
|
const files = Array.isArray(report) && report[0]?.files ? report[0].files : [];
|
|
33
33
|
const hasRootReadme = files.some((file) => /^readme(?:\.[^/]+)?$/i.test(file.path));
|
|
34
|
+
const hasGeneratedManifest = files.some((file) => file.path === "src/generated/opencode.managed.json");
|
|
35
|
+
const hasCursorPlugin = files.some((file) => file.path === ".cursor-plugin/plugin.json");
|
|
36
|
+
const hasClaudePlugin = files.some((file) => file.path === ".claude-plugin/plugin.json");
|
|
34
37
|
|
|
35
38
|
if (!hasRootReadme) {
|
|
36
39
|
console.error("Package guard failed: root README is missing from the packed tarball.");
|
|
@@ -38,4 +41,16 @@ if (!hasRootReadme) {
|
|
|
38
41
|
process.exit(1);
|
|
39
42
|
}
|
|
40
43
|
|
|
41
|
-
|
|
44
|
+
if (!hasGeneratedManifest) {
|
|
45
|
+
console.error("Package guard failed: src/generated/opencode.managed.json is missing from the packed tarball.");
|
|
46
|
+
console.error("Ensure 'src' is in package.json 'files' and the file is committed or generated before publish.");
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!hasCursorPlugin || !hasClaudePlugin) {
|
|
51
|
+
console.error("Package guard failed: .cursor-plugin/plugin.json and .claude-plugin/plugin.json must be in the packed tarball.");
|
|
52
|
+
console.error("Ensure '.cursor-plugin' and '.claude-plugin' are in package.json 'files'.");
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
console.log("Package guard passed: root README, opencode.managed.json, and plugin manifests are present in npm pack output.");
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Exit 0 if package.json version matches .cursor-plugin/plugin.json and .claude-plugin/plugin.json.
|
|
4
|
+
* Used in CI to validate release artifact sync.
|
|
5
|
+
*/
|
|
6
|
+
import fs from "node:fs";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
|
|
10
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const root = path.resolve(__dirname, "..");
|
|
12
|
+
|
|
13
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8"));
|
|
14
|
+
const cursorPlugin = JSON.parse(
|
|
15
|
+
fs.readFileSync(path.join(root, ".cursor-plugin", "plugin.json"), "utf8")
|
|
16
|
+
);
|
|
17
|
+
const claudePlugin = JSON.parse(
|
|
18
|
+
fs.readFileSync(path.join(root, ".claude-plugin", "plugin.json"), "utf8")
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
const expected = pkg.version;
|
|
22
|
+
if (cursorPlugin.version !== expected || claudePlugin.version !== expected) {
|
|
23
|
+
console.error(
|
|
24
|
+
"Version mismatch: package.json=%s, .cursor-plugin/plugin.json=%s, .claude-plugin/plugin.json=%s",
|
|
25
|
+
expected,
|
|
26
|
+
cursorPlugin.version,
|
|
27
|
+
claudePlugin.version
|
|
28
|
+
);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
@@ -133,9 +133,9 @@ function main() {
|
|
|
133
133
|
keywords: ["workflow", "cursor", "agents", "commands", "skills"],
|
|
134
134
|
license: pkg.license,
|
|
135
135
|
repository: repositoryUrl,
|
|
136
|
-
commands: "src/.agents/commands",
|
|
137
|
-
agents: "src/.agents/agents",
|
|
138
|
-
skills: "src/.agents/skills",
|
|
136
|
+
commands: "./src/.agents/commands",
|
|
137
|
+
agents: "./src/.agents/agents",
|
|
138
|
+
skills: "./src/.agents/skills",
|
|
139
139
|
};
|
|
140
140
|
|
|
141
141
|
const openCodeManaged = {
|
package/scripts/install-cli.mjs
CHANGED
|
@@ -137,19 +137,17 @@ function readGeneratedManifest() {
|
|
|
137
137
|
return manifest;
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
".agents/compound-workflow/commands",
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
PACKAGE_AGENT_ROOT,
|
|
152
|
-
];
|
|
140
|
+
let GENERATED_MANIFEST;
|
|
141
|
+
let PACKAGE_COMMAND_ROOT;
|
|
142
|
+
let PACKAGE_AGENT_ROOT;
|
|
143
|
+
let PACKAGE_SKILL_ROOT;
|
|
144
|
+
|
|
145
|
+
function getLegacyCommandRoots() {
|
|
146
|
+
return [".agents/compound-workflow/commands", PACKAGE_COMMAND_ROOT, "src/.agents/commands"];
|
|
147
|
+
}
|
|
148
|
+
function getLegacyAgentRoots() {
|
|
149
|
+
return [".agents/compound-workflow/agents", PACKAGE_AGENT_ROOT, "src/.agents/agents"];
|
|
150
|
+
}
|
|
153
151
|
|
|
154
152
|
function managedCommandPath(entry) {
|
|
155
153
|
const template = entry?.template;
|
|
@@ -167,14 +165,18 @@ function managedAgentPath(entry) {
|
|
|
167
165
|
}
|
|
168
166
|
|
|
169
167
|
function isManagedCommandPath(commandPath) {
|
|
170
|
-
return
|
|
168
|
+
return getLegacyCommandRoots().some((root) => commandPath.startsWith(`${root}/`));
|
|
171
169
|
}
|
|
172
170
|
|
|
173
171
|
function isManagedAgentPath(agentPath) {
|
|
174
|
-
return
|
|
172
|
+
return getLegacyAgentRoots().some((root) => agentPath.startsWith(`${root}/`));
|
|
175
173
|
}
|
|
176
174
|
|
|
177
|
-
function writeOpenCodeJson(targetRoot, dryRun) {
|
|
175
|
+
function writeOpenCodeJson(targetRoot, dryRun, isSelfInstall) {
|
|
176
|
+
const commandRoot = isSelfInstall ? "src/.agents/commands" : PACKAGE_COMMAND_ROOT;
|
|
177
|
+
const agentRoot = isSelfInstall ? "src/.agents/agents" : PACKAGE_AGENT_ROOT;
|
|
178
|
+
const skillRoot = isSelfInstall ? "src/.agents/skills" : PACKAGE_SKILL_ROOT;
|
|
179
|
+
|
|
178
180
|
const opencodeAbs = path.join(targetRoot, "opencode.json");
|
|
179
181
|
const existing = readJsonMaybe(opencodeAbs) ?? {};
|
|
180
182
|
const next = structuredClone(existing);
|
|
@@ -183,10 +185,9 @@ function writeOpenCodeJson(targetRoot, dryRun) {
|
|
|
183
185
|
next.skills = ensureObject(next.skills);
|
|
184
186
|
next.skills.paths = Array.isArray(next.skills.paths) ? next.skills.paths : [];
|
|
185
187
|
|
|
186
|
-
// Full cutover: remove old symlink-based managed path and use direct package skills path.
|
|
187
188
|
next.skills.paths = next.skills.paths.filter((p) => p !== ".agents/compound-workflow-skills");
|
|
188
|
-
if (!next.skills.paths.includes(
|
|
189
|
-
next.skills.paths.unshift(
|
|
189
|
+
if (!next.skills.paths.includes(skillRoot)) {
|
|
190
|
+
next.skills.paths.unshift(skillRoot);
|
|
190
191
|
}
|
|
191
192
|
|
|
192
193
|
next.command = ensureObject(next.command);
|
|
@@ -195,19 +196,17 @@ function writeOpenCodeJson(targetRoot, dryRun) {
|
|
|
195
196
|
const commands = GENERATED_MANIFEST.commands;
|
|
196
197
|
const agents = GENERATED_MANIFEST.agents;
|
|
197
198
|
|
|
198
|
-
// Upsert managed commands.
|
|
199
199
|
for (const command of commands) {
|
|
200
200
|
next.command[command.id] = {
|
|
201
201
|
...ensureObject(next.command[command.id]),
|
|
202
202
|
description: command.description,
|
|
203
203
|
agent: "build",
|
|
204
|
-
template: `@AGENTS.md\n@${
|
|
204
|
+
template: `@AGENTS.md\n@${commandRoot}/${command.rel}\nArguments: $ARGUMENTS\n`,
|
|
205
205
|
};
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
-
// Remove stale managed commands.
|
|
209
208
|
const managedCommandTargets = new Set(
|
|
210
|
-
commands.map((command) => `${
|
|
209
|
+
commands.map((command) => `${commandRoot}/${command.rel}`)
|
|
211
210
|
);
|
|
212
211
|
for (const [id, entry] of Object.entries(next.command)) {
|
|
213
212
|
const commandPath = managedCommandPath(entry);
|
|
@@ -215,20 +214,18 @@ function writeOpenCodeJson(targetRoot, dryRun) {
|
|
|
215
214
|
if (!managedCommandTargets.has(commandPath)) delete next.command[id];
|
|
216
215
|
}
|
|
217
216
|
|
|
218
|
-
// Upsert managed agents.
|
|
219
217
|
for (const agent of agents) {
|
|
220
218
|
next.agent[agent.id] = {
|
|
221
219
|
...ensureObject(next.agent[agent.id]),
|
|
222
220
|
description: agent.description,
|
|
223
221
|
mode: "subagent",
|
|
224
|
-
prompt: `{file:${
|
|
222
|
+
prompt: `{file:${agentRoot}/${agent.rel}}`,
|
|
225
223
|
permission: { ...ensureObject(next.agent[agent.id]?.permission), edit: "deny" },
|
|
226
224
|
};
|
|
227
225
|
}
|
|
228
226
|
|
|
229
|
-
// Remove stale managed agents.
|
|
230
227
|
const managedAgentTargets = new Set(
|
|
231
|
-
agents.map((agent) => `${
|
|
228
|
+
agents.map((agent) => `${agentRoot}/${agent.rel}`)
|
|
232
229
|
);
|
|
233
230
|
for (const [id, entry] of Object.entries(next.agent)) {
|
|
234
231
|
const agentPath = managedAgentPath(entry);
|
|
@@ -316,16 +313,45 @@ function ensureDirs(targetRoot, dryRun) {
|
|
|
316
313
|
}
|
|
317
314
|
}
|
|
318
315
|
|
|
316
|
+
function writePluginManifests(targetRoot, dryRun, isSelfInstall) {
|
|
317
|
+
const pathsBase = isSelfInstall ? "src/.agents" : "node_modules/compound-workflow/src/.agents";
|
|
318
|
+
const pathOverrides = {
|
|
319
|
+
commands: `${pathsBase}/commands`,
|
|
320
|
+
agents: `${pathsBase}/agents`,
|
|
321
|
+
skills: `${pathsBase}/skills`,
|
|
322
|
+
};
|
|
323
|
+
const cursorSrc = path.join(PACKAGE_ROOT, ".cursor-plugin", "plugin.json");
|
|
324
|
+
const claudeSrc = path.join(PACKAGE_ROOT, ".claude-plugin", "plugin.json");
|
|
325
|
+
const cursorManifest = readJsonMaybe(cursorSrc);
|
|
326
|
+
const claudeManifest = readJsonMaybe(claudeSrc);
|
|
327
|
+
if (!cursorManifest || !claudeManifest) return;
|
|
328
|
+
|
|
329
|
+
const cursorOut = { ...cursorManifest, ...pathOverrides };
|
|
330
|
+
const claudeOut = { ...claudeManifest, ...pathOverrides };
|
|
331
|
+
const cursorDir = path.join(targetRoot, ".cursor-plugin");
|
|
332
|
+
const claudeDir = path.join(targetRoot, ".claude-plugin");
|
|
333
|
+
|
|
334
|
+
if (dryRun) {
|
|
335
|
+
console.log("[dry-run] Would write .cursor-plugin/plugin.json and .claude-plugin/plugin.json");
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
fs.mkdirSync(cursorDir, { recursive: true });
|
|
339
|
+
fs.mkdirSync(claudeDir, { recursive: true });
|
|
340
|
+
fs.writeFileSync(path.join(cursorDir, "plugin.json"), JSON.stringify(cursorOut, null, 2) + "\n", "utf8");
|
|
341
|
+
fs.writeFileSync(path.join(claudeDir, "plugin.json"), JSON.stringify(claudeOut, null, 2) + "\n", "utf8");
|
|
342
|
+
console.log("Wrote: .cursor-plugin/plugin.json, .claude-plugin/plugin.json");
|
|
343
|
+
}
|
|
344
|
+
|
|
319
345
|
function reportOpenCodeIntegration(targetRoot, dryRun) {
|
|
320
346
|
if (dryRun) {
|
|
321
|
-
console.log("[dry-run] OpenCode integration check skipped.");
|
|
347
|
+
console.log("[dry-run] OpenCode integration check skipped (state would be updated by install).");
|
|
322
348
|
return;
|
|
323
349
|
}
|
|
324
350
|
|
|
325
351
|
const opencodeAbs = path.join(targetRoot, "opencode.json");
|
|
326
352
|
const opencode = readJsonMaybe(opencodeAbs) ?? {};
|
|
327
353
|
const skillPaths = Array.isArray(opencode?.skills?.paths) ? opencode.skills.paths : [];
|
|
328
|
-
const hasSkillPath = skillPaths.includes(PACKAGE_SKILL_ROOT);
|
|
354
|
+
const hasSkillPath = skillPaths.includes(PACKAGE_SKILL_ROOT) || skillPaths.includes("src/.agents/skills");
|
|
329
355
|
|
|
330
356
|
console.log(
|
|
331
357
|
"OpenCode integration:",
|
|
@@ -338,13 +364,24 @@ function main() {
|
|
|
338
364
|
const args = parseArgs(process.argv);
|
|
339
365
|
const targetRoot = realpathSafe(args.root);
|
|
340
366
|
|
|
367
|
+
try {
|
|
368
|
+
GENERATED_MANIFEST = readGeneratedManifest();
|
|
369
|
+
PACKAGE_COMMAND_ROOT = GENERATED_MANIFEST.commandRoot;
|
|
370
|
+
PACKAGE_AGENT_ROOT = GENERATED_MANIFEST.agentRoot;
|
|
371
|
+
PACKAGE_SKILL_ROOT = GENERATED_MANIFEST.skillsPath;
|
|
372
|
+
} catch (err) {
|
|
373
|
+
console.error("Error: OpenCode manifest not found. Run 'npm run generate:artifacts' in the package or reinstall compound-workflow.");
|
|
374
|
+
process.exit(2);
|
|
375
|
+
}
|
|
376
|
+
|
|
341
377
|
if (!fs.existsSync(PACKAGE_AGENTS_ROOT)) {
|
|
342
378
|
console.error("Error: package agents dir not found:", PACKAGE_AGENTS_ROOT);
|
|
343
379
|
process.exit(2);
|
|
344
380
|
}
|
|
345
381
|
|
|
382
|
+
const isSelfInstall = realpathSafe(targetRoot) === realpathSafe(PACKAGE_ROOT);
|
|
346
383
|
const pkgInTarget = path.join(targetRoot, "node_modules", "compound-workflow");
|
|
347
|
-
if (!fs.existsSync(pkgInTarget) && !args.dryRun) {
|
|
384
|
+
if (!isSelfInstall && !fs.existsSync(pkgInTarget) && !args.dryRun) {
|
|
348
385
|
console.error("Error: compound-workflow not found in project. Run: npm install compound-workflow");
|
|
349
386
|
process.exit(2);
|
|
350
387
|
}
|
|
@@ -353,7 +390,8 @@ function main() {
|
|
|
353
390
|
console.log("Package root:", PACKAGE_ROOT);
|
|
354
391
|
console.log("OpenCode CLI detected:", hasCommand("opencode") ? "yes" : "no");
|
|
355
392
|
|
|
356
|
-
writeOpenCodeJson(targetRoot, args.dryRun);
|
|
393
|
+
writeOpenCodeJson(targetRoot, args.dryRun, isSelfInstall);
|
|
394
|
+
writePluginManifests(targetRoot, args.dryRun, isSelfInstall);
|
|
357
395
|
reportOpenCodeIntegration(targetRoot, args.dryRun);
|
|
358
396
|
writeAgentsMd(targetRoot, args.dryRun);
|
|
359
397
|
ensureDirs(targetRoot, args.dryRun);
|
package/scripts/postinstall.mjs
CHANGED
|
@@ -38,7 +38,10 @@ function shouldSkip(targetRoot) {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
function run() {
|
|
41
|
-
|
|
41
|
+
let targetRoot = process.env.INIT_CWD ? path.resolve(process.env.INIT_CWD) : process.cwd();
|
|
42
|
+
if (!process.env.INIT_CWD) {
|
|
43
|
+
console.log("[compound-workflow] INIT_CWD not set; using process.cwd() as project root.");
|
|
44
|
+
}
|
|
42
45
|
const skipReason = shouldSkip(targetRoot);
|
|
43
46
|
if (skipReason) {
|
|
44
47
|
console.log(`[compound-workflow] postinstall skipped (${skipReason})`);
|