create-agdf 0.4.4 → 0.4.5

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.
@@ -555,22 +555,73 @@ function printOpenCodeStatus(report, json) {
555
555
  }
556
556
 
557
557
  function installCodexGlobalPlugin() {
558
+ const expectedVersion = pluginDefinition.version;
559
+
558
560
  try {
559
561
  execFileSync("codex", ["plugin", "marketplace", "add", "arndtgold/ai-native-governance-delivery-framework"], { stdio: "inherit" });
562
+ execFileSync("codex", ["plugin", "marketplace", "upgrade", "agdf"], { stdio: "inherit" });
560
563
  execFileSync("codex", ["plugin", "add", "agdf", "--marketplace", "agdf"], { stdio: "inherit" });
564
+ const listOutput = execFileSync("codex", ["plugin", "list"], { encoding: "utf8", stdio: "pipe" });
565
+ const installedVersion = pluginVersionFromList(listOutput, "agdf@agdf");
566
+ if (installedVersion !== expectedVersion) {
567
+ throw new Error(versionMismatchMessage("Codex", "agdf@agdf", expectedVersion, installedVersion, "codex plugin marketplace upgrade agdf && codex plugin add agdf --marketplace agdf"));
568
+ }
569
+ console.log(`AGDF Codex plugin version verified: ${installedVersion}.`);
561
570
  } catch (error) {
562
- throw new Error("Failed to install the AGDF Codex plugin. Make sure the Codex CLI is installed and available on PATH, then rerun this command.");
571
+ if (error.message?.startsWith("AGDF Codex plugin version mismatch")) throw error;
572
+ throw new Error(`Failed to install the AGDF Codex plugin. Make sure the Codex CLI is installed and available on PATH, then rerun this command. ${commandErrorText(error)}`.trim());
563
573
  }
564
574
  }
565
575
 
566
576
  function installClaudeGlobalPlugin() {
577
+ const expectedVersion = pluginDefinition.version;
578
+
567
579
  try {
568
- execFileSync("claude", ["plugin", "add", "arndtgold/ai-native-governance-delivery-framework"], { stdio: "inherit" });
569
- } catch {
570
- throw new Error("Failed to install the AGDF Claude Code plugin. Make sure the Claude Code CLI is installed and available on PATH, then rerun this command.");
580
+ execFileSync("claude", ["plugin", "marketplace", "add", "arndtgold/ai-native-governance-delivery-framework"], { stdio: "inherit" });
581
+ execFileSync("claude", ["plugin", "marketplace", "update", "agdf"], { stdio: "inherit" });
582
+ const beforeList = execFileSync("claude", ["plugin", "list"], { encoding: "utf8", stdio: "pipe" });
583
+ const alreadyInstalled = pluginListHasPlugin(beforeList, "agdf@agdf");
584
+ execFileSync("claude", ["plugin", alreadyInstalled ? "update" : "install", "agdf@agdf"], { stdio: "inherit" });
585
+ const afterList = execFileSync("claude", ["plugin", "list"], { encoding: "utf8", stdio: "pipe" });
586
+ const installedVersion = pluginVersionFromList(afterList, "agdf@agdf");
587
+ if (installedVersion) {
588
+ if (installedVersion !== expectedVersion) {
589
+ throw new Error(versionMismatchMessage("Claude Code", "agdf@agdf", expectedVersion, installedVersion, "claude plugin marketplace update agdf && claude plugin update agdf@agdf"));
590
+ }
591
+ console.log(`AGDF Claude Code plugin version verified: ${installedVersion}.`);
592
+ } else {
593
+ console.log("AGDF Claude Code plugin installed or updated. Claude Code did not expose a plugin version in `claude plugin list`; verify with `claude plugin list` after restart if needed.");
594
+ }
595
+ } catch (error) {
596
+ if (error.message?.startsWith("AGDF Claude Code plugin version mismatch")) throw error;
597
+ throw new Error(`Failed to install the AGDF Claude Code plugin. Make sure the Claude Code CLI is installed and available on PATH, then rerun this command. ${commandErrorText(error)}`.trim());
571
598
  }
572
599
  }
573
600
 
601
+ function commandErrorText(error) {
602
+ return (error.stderr || error.stdout || error.message || "").toString().trim();
603
+ }
604
+
605
+ function pluginListHasPlugin(output, pluginId) {
606
+ return output
607
+ .split(/\r?\n/)
608
+ .some((line) => line.includes(pluginId));
609
+ }
610
+
611
+ function pluginVersionFromList(output, pluginId) {
612
+ const escapedPluginId = pluginId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
613
+ const line = output
614
+ .split(/\r?\n/)
615
+ .find((entry) => new RegExp(`(^|\\s)${escapedPluginId}(\\s|$)`).test(entry));
616
+ if (!line) return "";
617
+ const versionMatch = line.match(/\b(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)\b/);
618
+ return versionMatch?.[1] ?? "";
619
+ }
620
+
621
+ function versionMismatchMessage(surface, pluginId, expectedVersion, installedVersion, correctiveCommand) {
622
+ return `AGDF ${surface} plugin version mismatch for ${pluginId}: expected ${expectedVersion}, observed ${installedVersion || "unknown"}. Refresh with: ${correctiveCommand}`;
623
+ }
624
+
574
625
  function loadAsset(relativePath) {
575
626
  return readFileSync(join(generatedRoot, relativePath), "utf8");
576
627
  }
@@ -586,6 +637,55 @@ function writeGeneratedFile(targetDir, relativePath, content, force, allowOverwr
586
637
  writeFileSync(outputPath, content, "utf8");
587
638
  }
588
639
 
640
+ function assertGeneratedWritePlan(targetDir, files, force) {
641
+ const blocked = files.find((file) => existsSync(join(targetDir, file.path)) && !force && !file.allowOverwrite);
642
+ if (blocked) {
643
+ throw new Error(`Refusing to overwrite existing file: ${blocked.path}. Re-run with --force if you want to replace it.`);
644
+ }
645
+ }
646
+
647
+ function isAgdfOwnedAgentsFile(content) {
648
+ return content.includes("## Surface Convention")
649
+ && content.includes("GitHub Copilot repository skills do not have a plugin namespace")
650
+ && content.includes("AGDF is agent-native first and CLI-verifiable by design");
651
+ }
652
+
653
+ function addCopilotAgentsFile(files, targetDir, force) {
654
+ const agentsPath = join(targetDir, "AGENTS.md");
655
+ if (!existsSync(agentsPath) || force) {
656
+ files.push({
657
+ path: "AGENTS.md",
658
+ content: loadAsset("AGENTS.md"),
659
+ });
660
+ return;
661
+ }
662
+
663
+ const existingAgents = readFileSync(agentsPath, "utf8");
664
+ if (isAgdfOwnedAgentsFile(existingAgents)) {
665
+ files.push({
666
+ path: "AGENTS.md",
667
+ content: loadAsset("AGENTS.md"),
668
+ allowOverwrite: true,
669
+ action: "refreshed",
670
+ });
671
+ return;
672
+ }
673
+
674
+ files.push({
675
+ path: agdfFragmentPath,
676
+ content: loadAsset("AGENTS.md"),
677
+ allowOverwrite: true,
678
+ action: "refreshed",
679
+ preserved: "AGENTS.md",
680
+ });
681
+ }
682
+
683
+ function shouldWriteLanguageConfig(target, targetDir, force) {
684
+ if (force) return true;
685
+ if ((target === "copilot" || target === "both") && existsSync(join(targetDir, ".agdf", "control", "config.json"))) return false;
686
+ return true;
687
+ }
688
+
589
689
  function addLanguageConfig(files, languagePreference) {
590
690
  files.push({
591
691
  path: join(".agdf", "control", "config.json"),
@@ -630,7 +730,7 @@ function generatedFilesForTarget(target, targetDir, force, languagePreference) {
630
730
  }
631
731
 
632
732
  if (target === "codex-repo" || target === "both") {
633
- addLanguageConfig(files, languagePreference);
733
+ if (shouldWriteLanguageConfig(target, targetDir, force)) addLanguageConfig(files, languagePreference);
634
734
  for (const codexPath of codexPluginFiles) {
635
735
  files.push({
636
736
  path: codexPath,
@@ -640,17 +740,15 @@ function generatedFilesForTarget(target, targetDir, force, languagePreference) {
640
740
  }
641
741
 
642
742
  if (target === "copilot" || target === "both") {
643
- if (target !== "both") addLanguageConfig(files, languagePreference);
644
- const agentsTargetPath = existsSync(join(targetDir, "AGENTS.md")) && !force ? agdfFragmentPath : "AGENTS.md";
645
- files.push({
646
- path: agentsTargetPath,
647
- content: loadAsset("AGENTS.md"),
648
- });
743
+ if (target !== "both" && shouldWriteLanguageConfig(target, targetDir, force)) addLanguageConfig(files, languagePreference);
744
+ addCopilotAgentsFile(files, targetDir, force);
649
745
 
650
746
  for (const controlPath of controlFiles) {
651
747
  files.push({
652
748
  path: controlPath,
653
749
  content: loadAsset(controlPath),
750
+ allowOverwrite: true,
751
+ action: "refreshed",
654
752
  });
655
753
  }
656
754
 
@@ -658,6 +756,8 @@ function generatedFilesForTarget(target, targetDir, force, languagePreference) {
658
756
  files.push({
659
757
  path: instructionPath,
660
758
  content: loadAsset(instructionPath),
759
+ allowOverwrite: true,
760
+ action: "refreshed",
661
761
  });
662
762
  }
663
763
 
@@ -665,6 +765,8 @@ function generatedFilesForTarget(target, targetDir, force, languagePreference) {
665
765
  files.push({
666
766
  path: skillPath,
667
767
  content: loadAsset(skillPath),
768
+ allowOverwrite: true,
769
+ action: "refreshed",
668
770
  });
669
771
  }
670
772
  }
@@ -701,7 +803,15 @@ function printNextSteps(target, destination, files, wroteAgentsFragment, wroteOp
701
803
  console.log("");
702
804
  console.log("Generated:");
703
805
  for (const file of files) {
704
- console.log(`- ${file.path}`);
806
+ const action = file.action ? `${file.action}: ` : "";
807
+ console.log(`- ${action}${file.path}`);
808
+ }
809
+
810
+ const preservedFiles = [...new Set(files.map((file) => file.preserved).filter(Boolean))];
811
+ if (preservedFiles.length > 0) {
812
+ console.log("");
813
+ console.log("Preserved:");
814
+ for (const preserved of preservedFiles) console.log(`- ${preserved}`);
705
815
  }
706
816
 
707
817
  console.log("");
@@ -2146,6 +2256,7 @@ async function main() {
2146
2256
  const wroteOpenCodeConfigFragment = files.some(file => file.path === openCodeConfigFragmentPath);
2147
2257
 
2148
2258
  try {
2259
+ assertGeneratedWritePlan(options.dir, files, options.force);
2149
2260
  for (const file of files) {
2150
2261
  writeGeneratedFile(options.dir, file.path, file.content, options.force, file.allowOverwrite);
2151
2262
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agdf",
3
- "version": "0.4.4",
3
+ "version": "0.4.5",
4
4
  "description": "Codex-first workflow skills for gated, auditable AI-assisted software delivery.",
5
5
  "author": {
6
6
  "name": "AI-native Governance & Delivery Framework",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "id": "agdf",
4
- "version": "0.4.4",
4
+ "version": "0.4.5",
5
5
  "displayName": "AI Governance & Delivery Framework",
6
6
  "developerName": "AI-native Governance & Delivery Framework",
7
7
  "description": "Codex-first workflow skills for gated, auditable AI-assisted software delivery.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-agdf",
3
- "version": "0.4.4",
3
+ "version": "0.4.5",
4
4
  "description": "Bootstrap AGDF repository-local plugin files, Copilot/OpenCode instructions, skills, control files and machine-readable checks.",
5
5
  "type": "module",
6
6
  "files": [