compound-workflow 1.7.2 → 1.7.3

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.7.2",
3
+ "version": "1.7.3",
4
4
  "description": "Clarify -> plan -> execute -> verify -> capture workflow for Cursor",
5
5
  "author": {
6
6
  "name": "Compound Workflow"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "compound-workflow",
3
- "version": "1.7.2",
3
+ "version": "1.7.3",
4
4
  "description": "Clarify → plan → execute → verify → capture. One Install action for Cursor, Claude, and OpenCode.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -34,7 +34,7 @@ When Cursor is detected (~/.cursor), registers the plugin so skills/commands app
34
34
  --root <dir> Project directory (default: cwd)
35
35
  --dry-run Print planned changes only
36
36
  --no-config Skip Repo Config Block reminder
37
- --no-register-cursor Do not register plugin with Cursor (skip apply to ~/.claude/)
37
+ --no-register-cursor Do not register plugin with Cursor
38
38
  --register-cursor Force registration with Cursor even if ~/.cursor not found
39
39
  `;
40
40
  (exitCode === 0 ? console.log : console.error)(msg.trimStart());
@@ -42,14 +42,13 @@ When Cursor is detected (~/.cursor), registers the plugin so skills/commands app
42
42
  }
43
43
 
44
44
  function parseArgs(argv) {
45
- const out = { root: process.cwd(), dryRun: false, noConfig: false, noRegisterCursor: false, registerCursor: false, verify: false };
45
+ const out = { root: process.cwd(), dryRun: false, noConfig: false, noRegisterCursor: false, registerCursor: false };
46
46
  for (let i = 2; i < argv.length; i++) {
47
47
  const arg = argv[i];
48
48
  if (arg === "--dry-run") out.dryRun = true;
49
49
  else if (arg === "--no-config") out.noConfig = true;
50
50
  else if (arg === "--no-register-cursor") out.noRegisterCursor = true;
51
51
  else if (arg === "--register-cursor") out.registerCursor = true;
52
- else if (arg === "--verify") out.verify = true;
53
52
  else if (arg === "--root") {
54
53
  const value = argv[i + 1];
55
54
  if (!value) usage(1);
@@ -342,13 +341,12 @@ function writePluginManifests(targetRoot, dryRun, isSelfInstall) {
342
341
  const claudeManifest = readJsonMaybe(claudeSrc);
343
342
  if (!cursorManifest || !claudeManifest) return;
344
343
 
345
- // Cursor supports full manifest with commands/agents/skills path overrides.
346
- // For commands/agents, use .cursor/ directories where symlinks are created
347
- // so Cursor can discover them properly. Skills still use source path.
344
+ // All Cursor paths point directly at the package source — no symlink indirection.
345
+ // This ensures frontmatter (descriptions) is parsed correctly by Cursor for all components.
348
346
  const cursorOut = {
349
347
  ...cursorManifest,
350
- commands: "./.cursor/commands",
351
- agents: "./.cursor/agents",
348
+ commands: `${pathsBase}/commands`,
349
+ agents: `${pathsBase}/agents`,
352
350
  skills: `${pathsBase}/skills`,
353
351
  };
354
352
  // Claude Code only accepts name, description, author in plugin.json.
@@ -428,411 +426,24 @@ function writePluginManifests(targetRoot, dryRun, isSelfInstall) {
428
426
  console.log("Wrote: .cursor-plugin/plugin.json, .claude-plugin/plugin.json, .cursor-plugin/registration.json" + (isSelfInstall ? "" : ", .claude-plugin/marketplace.json"));
429
427
  }
430
428
 
431
- /**
432
- * Cursor discovers skills only from .agents/skills, .cursor/skills, ~/.cursor/skills.
433
- * Populate .cursor/skills/ with symlinks to the package skills so Cursor finds them.
434
- */
435
- function syncCursorSkills(targetRoot, dryRun, isSelfInstall) {
436
- const packageSkillsAbs = isSelfInstall
437
- ? path.join(PACKAGE_ROOT, "src", ".agents", "skills")
438
- : path.join(targetRoot, "node_modules", "compound-workflow", "src", ".agents", "skills");
439
- if (!fs.existsSync(packageSkillsAbs)) return;
440
-
441
- const cursorSkillsDir = path.join(targetRoot, ".cursor", "skills");
442
- let entries;
443
- try {
444
- entries = fs.readdirSync(packageSkillsAbs, { withFileTypes: true });
445
- } catch {
446
- return;
447
- }
448
-
449
- const skillDirs = entries.filter((e) => e.isDirectory() && fs.existsSync(path.join(packageSkillsAbs, e.name, "SKILL.md"))).map((e) => e.name);
450
- if (skillDirs.length === 0) return;
451
-
452
- if (dryRun) {
453
- console.log("[dry-run] Would symlink", skillDirs.length, "skills into .cursor/skills/");
454
- return;
455
- }
456
-
457
- fs.mkdirSync(cursorSkillsDir, { recursive: true });
458
- const packageSkillsReal = realpathSafe(packageSkillsAbs);
459
- const skillSet = new Set(skillDirs);
460
-
461
- // Prune: remove symlinks that point at our package but are no longer in the package
462
- try {
463
- for (const entry of fs.readdirSync(cursorSkillsDir, { withFileTypes: true })) {
464
- if (!entry.isSymbolicLink()) continue;
465
- const linkPath = path.join(cursorSkillsDir, entry.name);
466
- try {
467
- const resolved = realpathSafe(linkPath);
468
- if (!resolved.startsWith(packageSkillsReal + path.sep) && resolved !== packageSkillsReal) continue;
469
- const base = path.basename(resolved);
470
- if (skillSet.has(base)) continue;
471
- fs.rmSync(linkPath);
472
- } catch {
473
- /* ignore broken symlinks or permission errors */
474
- }
475
- }
476
- } catch {
477
- /* .cursor/skills not readable */
478
- }
479
-
480
- for (const name of skillDirs) {
481
- const linkPath = path.join(cursorSkillsDir, name);
482
- const targetPath = path.join(packageSkillsAbs, name);
483
- try {
484
- if (fs.existsSync(linkPath)) {
485
- const stat = fs.lstatSync(linkPath);
486
- if (!stat.isSymbolicLink()) continue;
487
- try {
488
- if (realpathSafe(linkPath) !== realpathSafe(targetPath)) continue;
489
- } catch {
490
- continue;
491
- }
492
- fs.rmSync(linkPath);
493
- }
494
- fs.symlinkSync(targetPath, linkPath, "dir");
495
- } catch (err) {
496
- if (err.code === "EPERM" && process.platform === "win32") {
497
- try {
498
- fs.symlinkSync(targetPath, linkPath, "junction");
499
- } catch {
500
- console.warn("[cursor] Could not symlink skill", name, err.message);
501
- }
502
- } else {
503
- console.warn("[cursor] Could not symlink skill", name, err.message);
504
- }
505
- }
506
- }
507
- console.log("Synced", skillDirs.length, "skills to .cursor/skills/");
508
- }
509
-
510
- /**
511
- * Cursor discovers commands from .cursor/commands.
512
- * Populate .cursor/commands/ with symlinks to the package commands so Cursor finds them.
513
- */
514
- function syncCursorCommands(targetRoot, dryRun, isSelfInstall) {
515
- const packageCommandsAbs = isSelfInstall
516
- ? path.join(PACKAGE_ROOT, "src", ".agents", "commands")
517
- : path.join(targetRoot, "node_modules", "compound-workflow", "src", ".agents", "commands");
518
- if (!fs.existsSync(packageCommandsAbs)) return;
519
-
520
- const cursorCommandsDir = path.join(targetRoot, ".cursor", "commands");
521
- let entries;
522
- try {
523
- entries = fs.readdirSync(packageCommandsAbs, { withFileTypes: true });
524
- } catch {
525
- return;
526
- }
527
-
528
- // Filter .md files that are commands
529
- const commandFiles = entries.filter((e) => e.isFile() && e.name.endsWith(".md")).map((e) => e.name);
530
- if (commandFiles.length === 0) return;
531
-
532
- if (dryRun) {
533
- console.log("[dry-run] Would symlink", commandFiles.length, "commands into .cursor/commands/");
534
- return;
535
- }
536
-
537
- fs.mkdirSync(cursorCommandsDir, { recursive: true });
538
- const packageCommandsReal = realpathSafe(packageCommandsAbs);
539
- const commandSet = new Set(commandFiles);
540
-
541
- // Prune: remove symlinks that point at our package but are no longer in the package
542
- try {
543
- for (const entry of fs.readdirSync(cursorCommandsDir, { withFileTypes: true })) {
544
- if (!entry.isSymbolicLink()) continue;
545
- const linkPath = path.join(cursorCommandsDir, entry.name);
546
- try {
547
- const resolved = realpathSafe(linkPath);
548
- if (!resolved.startsWith(packageCommandsReal + path.sep) && resolved !== packageCommandsReal) continue;
549
- const base = path.basename(resolved);
550
- if (commandSet.has(base)) continue;
551
- fs.rmSync(linkPath);
552
- } catch {
553
- /* ignore broken symlinks or permission errors */
554
- }
555
- }
556
- } catch {
557
- /* .cursor/commands not readable */
558
- }
559
-
560
- for (const name of commandFiles) {
561
- const linkPath = path.join(cursorCommandsDir, name);
562
- const targetPath = path.join(packageCommandsAbs, name);
563
- try {
564
- if (fs.existsSync(linkPath)) {
565
- const stat = fs.lstatSync(linkPath);
566
- if (!stat.isSymbolicLink()) continue;
567
- try {
568
- if (realpathSafe(linkPath) !== realpathSafe(targetPath)) continue;
569
- } catch {
570
- continue;
571
- }
572
- fs.rmSync(linkPath);
573
- }
574
- fs.symlinkSync(targetPath, linkPath, "file");
575
- } catch (err) {
576
- console.warn("[cursor] Could not symlink command", name, err.message);
577
- }
578
- }
579
- console.log("Synced", commandFiles.length, "commands to .cursor/commands/");
580
- }
581
-
582
- /**
583
- * Cursor discovers agents from .cursor/agents.
584
- * Populate .cursor/agents/ with symlinks to the package agents so Cursor finds them.
585
- * Preserves subdirectory structure (research/, workflow/, review/).
586
- */
587
- function syncCursorAgents(targetRoot, dryRun, isSelfInstall) {
588
- const packageAgentsAbs = isSelfInstall
589
- ? path.join(PACKAGE_ROOT, "src", ".agents", "agents")
590
- : path.join(targetRoot, "node_modules", "compound-workflow", "src", ".agents", "agents");
591
- if (!fs.existsSync(packageAgentsAbs)) return;
592
-
593
- const cursorAgentsDir = path.join(targetRoot, ".cursor", "agents");
594
-
595
- // Get all agent files from manifest (these include subdir paths like "research/repo-research-analyst.md")
596
- const agentRels = GENERATED_MANIFEST.agents.map((a) => a.rel);
597
- if (agentRels.length === 0) return;
598
-
599
- if (dryRun) {
600
- console.log("[dry-run] Would symlink", agentRels.length, "agents into .cursor/agents/");
601
- return;
602
- }
603
-
604
- fs.mkdirSync(cursorAgentsDir, { recursive: true });
605
- const packageAgentsReal = realpathSafe(packageAgentsAbs);
606
- const agentSet = new Set(agentRels);
607
-
608
- // Build set of valid subdirectories to preserve structure
609
- const validSubdirs = new Set();
610
- for (const rel of agentRels) {
611
- const subdir = path.dirname(rel);
612
- if (subdir !== ".") validSubdirs.add(subdir);
613
- }
614
429
 
615
- // Prune: remove symlinks that point at our package but are no longer in the manifest
616
- try {
617
- for (const entry of fs.readdirSync(cursorAgentsDir, { withFileTypes: true })) {
618
- if (entry.isDirectory()) {
619
- // Check if this subdir is still valid
620
- if (!validSubdirs.has(entry.name)) {
621
- // Remove the entire stale subdirectory
622
- fs.rmSync(path.join(cursorAgentsDir, entry.name), { recursive: true, force: true });
623
- continue;
624
- }
625
- // Prune stale symlinks within valid subdirectories
626
- const subdirPath = path.join(cursorAgentsDir, entry.name);
627
- for (const subEntry of fs.readdirSync(subdirPath, { withFileTypes: true })) {
628
- if (!subEntry.isSymbolicLink()) continue;
629
- const linkPath = path.join(subdirPath, subEntry.name);
630
- try {
631
- const resolved = realpathSafe(linkPath);
632
- if (!resolved.startsWith(packageAgentsReal + path.sep) && resolved !== packageAgentsReal) continue;
633
- const relFromPackage = path.relative(packageAgentsAbs, resolved);
634
- if (agentSet.has(relFromPackage)) continue;
635
- fs.rmSync(linkPath);
636
- } catch {
637
- /* ignore broken symlinks */
638
- }
639
- }
640
- } else if (entry.isSymbolicLink()) {
641
- // Handle flat symlinks (if any were created at root level)
642
- const linkPath = path.join(cursorAgentsDir, entry.name);
643
- try {
644
- const resolved = realpathSafe(linkPath);
645
- if (!resolved.startsWith(packageAgentsReal + path.sep) && resolved !== packageAgentsReal) continue;
646
- const relFromPackage = path.relative(packageAgentsAbs, resolved);
647
- if (agentSet.has(relFromPackage)) continue;
648
- fs.rmSync(linkPath);
649
- } catch {
650
- /* ignore broken symlinks */
651
- }
652
- }
653
- }
654
- } catch {
655
- /* .cursor/agents not readable */
656
- }
657
-
658
- // Create symlinks preserving subdirectory structure
659
- for (const rel of agentRels) {
660
- const targetPath = path.join(packageAgentsAbs, rel);
661
- const linkPath = path.join(cursorAgentsDir, rel);
662
-
663
- // Ensure subdirectory exists
664
- const subdir = path.dirname(rel);
665
- if (subdir !== ".") {
666
- fs.mkdirSync(path.join(cursorAgentsDir, subdir), { recursive: true });
667
- }
668
-
669
- try {
670
- if (fs.existsSync(linkPath)) {
671
- const stat = fs.lstatSync(linkPath);
672
- if (!stat.isSymbolicLink()) continue;
673
- try {
674
- if (realpathSafe(linkPath) !== realpathSafe(targetPath)) continue;
675
- } catch {
676
- continue;
677
- }
678
- fs.rmSync(linkPath);
679
- }
680
- fs.symlinkSync(targetPath, linkPath, "file");
681
- } catch (err) {
682
- console.warn("[cursor] Could not symlink agent", rel, err.message);
683
- }
684
- }
685
- console.log("Synced", agentRels.length, "agents to .cursor/agents/");
686
- }
687
430
 
688
431
  function cursorDetected() {
689
432
  return fs.existsSync(path.join(os.homedir(), ".cursor"));
690
433
  }
691
434
 
692
- /**
693
- * Verifies plugin integrity by checking all symlinks in .cursor/ directories
694
- * match the expected state from GENERATED_MANIFEST.
695
- * Returns { ok: boolean, issues: string[] }
696
- */
697
- function verifyPluginIntegrity(targetRoot, isSelfInstall) {
698
- const issues = [];
699
- const packageRoot = isSelfInstall
700
- ? PACKAGE_ROOT
701
- : path.join(targetRoot, "node_modules", "compound-workflow");
702
-
703
- // Verify skills
704
- const cursorSkillsDir = path.join(targetRoot, ".cursor", "skills");
705
- const packageSkillsDir = path.join(packageRoot, "src", ".agents", "skills");
706
- if (fs.existsSync(packageSkillsDir)) {
707
- const expectedSkills = new Set(
708
- fs.readdirSync(packageSkillsDir, { withFileTypes: true })
709
- .filter((e) => e.isDirectory() && fs.existsSync(path.join(packageSkillsDir, e.name, "SKILL.md")))
710
- .map((e) => e.name)
711
- );
712
- if (fs.existsSync(cursorSkillsDir)) {
713
- const actualSkills = fs.readdirSync(cursorSkillsDir, { withFileTypes: true })
714
- .filter((e) => e.isSymbolicLink())
715
- .map((e) => e.name);
716
- for (const skill of expectedSkills) {
717
- if (!actualSkills.includes(skill)) {
718
- issues.push(`Missing skill symlink: .cursor/skills/${skill}`);
719
- }
720
- }
721
- for (const skill of actualSkills) {
722
- if (!expectedSkills.has(skill)) {
723
- issues.push(`Stale skill symlink: .cursor/skills/${skill}`);
724
- }
725
- }
726
- } else if (expectedSkills.size > 0) {
727
- issues.push(`Missing .cursor/skills/ directory (${expectedSkills.size} expected)`);
728
- }
729
- }
730
-
731
- // Verify commands
732
- const cursorCommandsDir = path.join(targetRoot, ".cursor", "commands");
733
- const packageCommandsDir = path.join(packageRoot, "src", ".agents", "commands");
734
- if (fs.existsSync(packageCommandsDir)) {
735
- const expectedCommands = new Set(
736
- fs.readdirSync(packageCommandsDir, { withFileTypes: true })
737
- .filter((e) => e.isFile() && e.name.endsWith(".md"))
738
- .map((e) => e.name)
739
- );
740
- if (fs.existsSync(cursorCommandsDir)) {
741
- const actualCommands = fs.readdirSync(cursorCommandsDir, { withFileTypes: true })
742
- .filter((e) => e.isSymbolicLink())
743
- .map((e) => e.name);
744
- for (const cmd of expectedCommands) {
745
- if (!actualCommands.includes(cmd)) {
746
- issues.push(`Missing command symlink: .cursor/commands/${cmd}`);
747
- }
748
- }
749
- for (const cmd of actualCommands) {
750
- if (!expectedCommands.has(cmd)) {
751
- issues.push(`Stale command symlink: .cursor/commands/${cmd}`);
752
- }
753
- }
754
- } else if (expectedCommands.size > 0) {
755
- issues.push(`Missing .cursor/commands/ directory (${expectedCommands.size} expected)`);
756
- }
757
- }
758
-
759
- // Verify agents
760
- const cursorAgentsDir = path.join(targetRoot, ".cursor", "agents");
761
- const packageAgentsDir = path.join(packageRoot, "src", ".agents", "agents");
762
- if (fs.existsSync(packageAgentsDir)) {
763
- // Recursively get all .md files from package agents dir
764
- const expectedAgents = [];
765
- function collectAgents(dir, prefix = "") {
766
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
767
- const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
768
- if (entry.isDirectory()) {
769
- collectAgents(path.join(dir, entry.name), relPath);
770
- } else if (entry.isFile() && entry.name.endsWith(".md")) {
771
- expectedAgents.push(relPath);
772
- }
773
- }
774
- }
775
- collectAgents(packageAgentsDir);
776
- const expectedSet = new Set(expectedAgents);
777
-
778
- if (fs.existsSync(cursorAgentsDir)) {
779
- const actualAgents = [];
780
- function collectActualAgents(dir, prefix = "") {
781
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
782
- const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
783
- if (entry.isDirectory()) {
784
- collectActualAgents(path.join(dir, entry.name), relPath);
785
- } else if (entry.isSymbolicLink()) {
786
- actualAgents.push(relPath);
787
- }
788
- }
789
- }
790
- collectActualAgents(cursorAgentsDir);
791
- const actualSet = new Set(actualAgents);
792
-
793
- for (const agent of expectedAgents) {
794
- if (!actualSet.has(agent)) {
795
- issues.push(`Missing agent symlink: .cursor/agents/${agent}`);
796
- }
797
- }
798
- for (const agent of actualAgents) {
799
- if (!expectedSet.has(agent)) {
800
- issues.push(`Stale agent symlink: .cursor/agents/${agent}`);
801
- }
802
- }
803
- } else if (expectedAgents.length > 0) {
804
- issues.push(`Missing .cursor/agents/ directory (${expectedAgents.length} expected)`);
805
- }
806
- }
807
-
808
- return { ok: issues.length === 0, issues };
809
- }
810
435
 
811
436
  function applyCursorRegistration(targetRoot, dryRun, noRegisterCursor, forceRegister, isSelfInstall) {
812
- const claudePluginsDir = path.join(os.homedir(), ".claude", "plugins");
813
- const installedPath = path.join(claudePluginsDir, "installed_plugins.json");
814
- const settingsPath = path.join(os.homedir(), ".claude", "settings.json");
815
-
816
- const pluginVersion = (() => {
817
- try {
818
- const pkgPath = path.join(PACKAGE_ROOT, "package.json");
819
- return JSON.parse(fs.readFileSync(pkgPath, "utf8")).version || "0.0.0";
820
- } catch {
821
- return "0.0.0";
822
- }
823
- })();
824
-
825
437
  const projectRoot = isSelfInstall ? PACKAGE_ROOT : targetRoot;
826
- const pluginId = "compound-workflow@local";
438
+ const pluginId = "compound-workflow@compound-workflow-local";
827
439
 
828
440
  if (dryRun) {
829
441
  console.log("[dry-run] Would register Claude plugin (project-scoped) at:", projectRoot);
830
442
  return;
831
443
  }
832
444
 
833
- // Registration is always project-scoped: write only to <project>/.claude/settings.json.
834
- // Claude Code manages ~/.claude/plugins/installed_plugins.json itself via marketplace flow;
835
- // writing to user-level files causes "unregistered local marketplace" errors on startup.
445
+ // Registration is strictly project-scoped: write only to <project>/.claude/settings.json.
446
+ // Never touch ~/.claude — Claude Code manages user-level plugin state itself.
836
447
  const projectSettingsPath = path.join(projectRoot, ".claude", "settings.json");
837
448
  let projectSettings = {};
838
449
  if (fs.existsSync(projectSettingsPath)) {
@@ -846,31 +457,11 @@ function applyCursorRegistration(targetRoot, dryRun, noRegisterCursor, forceRegi
846
457
  }
847
458
  projectSettings.extraKnownMarketplaces = ensureObject(projectSettings.extraKnownMarketplaces);
848
459
  projectSettings.extraKnownMarketplaces["compound-workflow-local"] = {
849
- source: { source: "file", path: ".claude-plugin/marketplace.json" },
460
+ source: { source: "file", path: "." },
850
461
  };
851
462
  fs.mkdirSync(path.join(projectRoot, ".claude"), { recursive: true });
852
463
  fs.writeFileSync(projectSettingsPath, JSON.stringify(projectSettings, null, 2) + "\n", "utf8");
853
464
 
854
- // Clean up any stale user-level enabledPlugins entries left by previous install versions.
855
- // These cause "unregistered local marketplace" errors on every Claude Code startup.
856
- if (fs.existsSync(settingsPath)) {
857
- try {
858
- let userSettings = readJsonMaybe(settingsPath) ?? {};
859
- const staleIds = ["compound-workflow@local", "compound-workflow@compound-workflow-local"];
860
- let changed = false;
861
- for (const id of staleIds) {
862
- if (userSettings?.enabledPlugins?.[id] !== undefined) {
863
- delete userSettings.enabledPlugins[id];
864
- changed = true;
865
- }
866
- }
867
- if (changed) {
868
- fs.writeFileSync(settingsPath, JSON.stringify(userSettings, null, 2) + "\n", "utf8");
869
- console.log("Cleaned up stale compound-workflow entries from ~/.claude/settings.json");
870
- }
871
- } catch { /* ignore */ }
872
- }
873
-
874
465
  console.log("Registered compound-workflow with Claude Code (project-scoped).");
875
466
  if (!isSelfInstall) {
876
467
  console.log(" Claude Code 2.1+: open /plugin, go to Discover; install 'compound-workflow' from marketplace 'compound-workflow-local', or run: claude --plugin-dir ./node_modules/compound-workflow");
@@ -910,31 +501,6 @@ function main() {
910
501
  const args = parseArgs(process.argv);
911
502
  const targetRoot = realpathSafe(args.root);
912
503
 
913
- // Handle verification mode early (no manifest needed)
914
- if (args.verify) {
915
- console.log("Verifying plugin integrity...");
916
- const isSelfInstall = realpathSafe(targetRoot) === realpathSafe(PACKAGE_ROOT);
917
- // Try to read manifest for accurate verification, but continue without it
918
- try {
919
- GENERATED_MANIFEST = readGeneratedManifest();
920
- } catch {
921
- console.warn("Warning: Could not read generated manifest, using filesystem scan only");
922
- GENERATED_MANIFEST = { commands: [], agents: [] };
923
- }
924
- const result = verifyPluginIntegrity(targetRoot, isSelfInstall);
925
- if (result.ok) {
926
- console.log("Plugin integrity: OK (all symlinks present and valid)");
927
- process.exit(0);
928
- } else {
929
- console.error("Plugin integrity issues found:");
930
- for (const issue of result.issues) {
931
- console.error(` - ${issue}`);
932
- }
933
- console.error("\nRun 'npx compound-workflow install' to fix.");
934
- process.exit(1);
935
- }
936
- }
937
-
938
504
  const genScript = path.join(PACKAGE_ROOT, "scripts", "generate-platform-artifacts.mjs");
939
505
  if (fs.existsSync(genScript)) {
940
506
  console.log("[compound-workflow] Regenerating manifest from package source...");
@@ -977,9 +543,6 @@ function main() {
977
543
 
978
544
  writeOpenCodeJson(targetRoot, args.dryRun, isSelfInstall);
979
545
  writePluginManifests(targetRoot, args.dryRun, isSelfInstall);
980
- syncCursorSkills(targetRoot, args.dryRun, isSelfInstall);
981
- syncCursorCommands(targetRoot, args.dryRun, isSelfInstall);
982
- syncCursorAgents(targetRoot, args.dryRun, isSelfInstall);
983
546
  applyCursorRegistration(targetRoot, args.dryRun, args.noRegisterCursor, args.registerCursor, isSelfInstall);
984
547
  reportOpenCodeIntegration(targetRoot, args.dryRun);
985
548
  writeAgentsMd(targetRoot, args.dryRun);