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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "compound-workflow",
3
- "version": "1.4.6",
3
+ "version": "1.5.0",
4
4
  "description": "Clarify -> plan -> execute -> verify -> capture workflow: commands, skills, and agents for Claude Code",
5
5
  "author": {
6
6
  "name": "Compound Workflow"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "compound-workflow",
3
- "version": "1.4.6",
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.4.7",
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
- console.log("Package guard passed: root README is present in npm pack output.");
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 = {
@@ -137,19 +137,17 @@ function readGeneratedManifest() {
137
137
  return manifest;
138
138
  }
139
139
 
140
- const GENERATED_MANIFEST = readGeneratedManifest();
141
- const PACKAGE_COMMAND_ROOT = GENERATED_MANIFEST.commandRoot;
142
- const PACKAGE_AGENT_ROOT = GENERATED_MANIFEST.agentRoot;
143
- const PACKAGE_SKILL_ROOT = GENERATED_MANIFEST.skillsPath;
144
-
145
- const LEGACY_MANAGED_COMMAND_ROOTS = [
146
- ".agents/compound-workflow/commands",
147
- PACKAGE_COMMAND_ROOT,
148
- ];
149
- const LEGACY_MANAGED_AGENT_ROOTS = [
150
- ".agents/compound-workflow/agents",
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 LEGACY_MANAGED_COMMAND_ROOTS.some((root) => commandPath.startsWith(`${root}/`));
168
+ return getLegacyCommandRoots().some((root) => commandPath.startsWith(`${root}/`));
171
169
  }
172
170
 
173
171
  function isManagedAgentPath(agentPath) {
174
- return LEGACY_MANAGED_AGENT_ROOTS.some((root) => agentPath.startsWith(`${root}/`));
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(PACKAGE_SKILL_ROOT)) {
189
- next.skills.paths.unshift(PACKAGE_SKILL_ROOT);
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@${PACKAGE_COMMAND_ROOT}/${command.rel}\nArguments: $ARGUMENTS\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) => `${PACKAGE_COMMAND_ROOT}/${command.rel}`)
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:${PACKAGE_AGENT_ROOT}/${agent.rel}}`,
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) => `${PACKAGE_AGENT_ROOT}/${agent.rel}`)
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);
@@ -38,7 +38,10 @@ function shouldSkip(targetRoot) {
38
38
  }
39
39
 
40
40
  function run() {
41
- const targetRoot = process.env.INIT_CWD ? path.resolve(process.env.INIT_CWD) : "";
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})`);