agent-conf 1.0.1 → 2.0.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/dist/index.js CHANGED
@@ -16,7 +16,7 @@ import {
16
16
 
17
17
  // src/cli.ts
18
18
  import { Command } from "commander";
19
- import pc12 from "picocolors";
19
+ import pc11 from "picocolors";
20
20
 
21
21
  // src/commands/check.ts
22
22
  import * as fs2 from "fs/promises";
@@ -66,7 +66,7 @@ var CONFIG_DIR = ".agent-conf";
66
66
  var LOCKFILE_NAME = "lockfile.json";
67
67
  var CLI_VERSION = "0.1.0";
68
68
  function getBuildCommit() {
69
- return true ? "b36711a163f8a165708aa21fbef7179ba52c3650" : "unknown";
69
+ return true ? "af06a802f86c2ea72029e3314e6e82fbe39ca33b" : "unknown";
70
70
  }
71
71
  function getLockfilePath(targetDir) {
72
72
  return path.join(targetDir, CONFIG_DIR, LOCKFILE_NAME);
@@ -254,7 +254,7 @@ var COMMANDS = {
254
254
  },
255
255
  "upgrade-cli": {
256
256
  description: "Upgrade the CLI to latest version",
257
- options: ["-r", "--repo", "-y", "--yes"]
257
+ options: ["-y", "--yes"]
258
258
  },
259
259
  "init-canonical-repo": {
260
260
  description: "Scaffold a new canonical repository",
@@ -457,39 +457,6 @@ async function promptCompletionInstall() {
457
457
  import * as prompts2 from "@clack/prompts";
458
458
  import pc4 from "picocolors";
459
459
 
460
- // src/core/global-config.ts
461
- import * as fs4 from "fs/promises";
462
- import * as os2 from "os";
463
- import * as path4 from "path";
464
- var CONFIG_DIR2 = path4.join(os2.homedir(), ".agent-conf");
465
- var CONFIG_FILE = path4.join(CONFIG_DIR2, "config.json");
466
- async function readGlobalConfig() {
467
- try {
468
- const content = await fs4.readFile(CONFIG_FILE, "utf-8");
469
- return JSON.parse(content);
470
- } catch {
471
- return {};
472
- }
473
- }
474
- async function writeGlobalConfig(config) {
475
- await fs4.mkdir(CONFIG_DIR2, { recursive: true });
476
- await fs4.writeFile(CONFIG_FILE, `${JSON.stringify(config, null, 2)}
477
- `, "utf-8");
478
- }
479
- async function updateGlobalConfig(updates) {
480
- const existing = await readGlobalConfig();
481
- const updated = { ...existing, ...updates };
482
- await writeGlobalConfig(updated);
483
- return updated;
484
- }
485
- async function getCliRepository() {
486
- const config = await readGlobalConfig();
487
- return config.cliRepository;
488
- }
489
- async function setCliRepository(repo) {
490
- await updateGlobalConfig({ cliRepository: repo });
491
- }
492
-
493
460
  // src/utils/logger.ts
494
461
  import ora from "ora";
495
462
  import pc3 from "picocolors";
@@ -535,50 +502,25 @@ function formatPath(p, cwd = process.cwd()) {
535
502
  async function configShowCommand() {
536
503
  console.log();
537
504
  prompts2.intro(pc4.bold("agent-conf config"));
538
- const config = await readGlobalConfig();
539
505
  console.log();
540
506
  console.log(pc4.bold("Global Configuration:"));
541
507
  console.log();
542
- if (config.cliRepository) {
543
- console.log(` cli-repo: ${pc4.cyan(config.cliRepository)}`);
544
- } else {
545
- console.log(` cli-repo: ${pc4.dim("(not set)")}`);
546
- }
508
+ console.log(pc4.dim(" No configuration options available."));
547
509
  console.log();
548
510
  console.log(pc4.dim("Config location: ~/.agent-conf/config.json"));
549
511
  prompts2.outro("");
550
512
  }
551
513
  async function configGetCommand(key) {
552
514
  const logger = createLogger();
553
- switch (key) {
554
- case "cli-repo": {
555
- const value = await getCliRepository();
556
- if (value) {
557
- console.log(value);
558
- } else {
559
- logger.warn("cli-repo is not set");
560
- process.exit(1);
561
- }
562
- break;
563
- }
564
- default:
565
- logger.error(`Unknown config key: ${key}`);
566
- logger.info("Available keys: cli-repo");
567
- process.exit(1);
568
- }
515
+ logger.error(`Unknown config key: ${key}`);
516
+ logger.info("No configuration options available.");
517
+ process.exit(1);
569
518
  }
570
- async function configSetCommand(key, value) {
519
+ async function configSetCommand(key, _value) {
571
520
  const logger = createLogger();
572
- switch (key) {
573
- case "cli-repo":
574
- await setCliRepository(value);
575
- logger.info(`Set cli-repo to: ${value}`);
576
- break;
577
- default:
578
- logger.error(`Unknown config key: ${key}`);
579
- logger.info("Available keys: cli-repo");
580
- process.exit(1);
581
- }
521
+ logger.error(`Unknown config key: ${key}`);
522
+ logger.info("No configuration options available.");
523
+ process.exit(1);
582
524
  }
583
525
 
584
526
  // src/commands/init.ts
@@ -586,16 +528,16 @@ import * as prompts4 from "@clack/prompts";
586
528
  import pc6 from "picocolors";
587
529
 
588
530
  // src/core/sync.ts
589
- import * as fs6 from "fs/promises";
590
- import * as path6 from "path";
531
+ import * as fs5 from "fs/promises";
532
+ import * as path5 from "path";
591
533
  import fg from "fast-glob";
592
534
 
593
535
  // src/core/merge.ts
594
- import * as fs5 from "fs/promises";
595
- import * as path5 from "path";
536
+ import * as fs4 from "fs/promises";
537
+ import * as path4 from "path";
596
538
  async function readFileIfExists(filePath) {
597
539
  try {
598
- return await fs5.readFile(filePath, "utf-8");
540
+ return await fs4.readFile(filePath, "utf-8");
599
541
  } catch (error) {
600
542
  if (error.code === "ENOENT") {
601
543
  return null;
@@ -604,9 +546,9 @@ async function readFileIfExists(filePath) {
604
546
  }
605
547
  }
606
548
  async function gatherExistingContent(targetDir) {
607
- const agentsMdPath = path5.join(targetDir, "AGENTS.md");
608
- const rootClaudeMdPath = path5.join(targetDir, "CLAUDE.md");
609
- const dotClaudeClaudeMdPath = path5.join(targetDir, ".claude", "CLAUDE.md");
549
+ const agentsMdPath = path4.join(targetDir, "AGENTS.md");
550
+ const rootClaudeMdPath = path4.join(targetDir, "CLAUDE.md");
551
+ const dotClaudeClaudeMdPath = path4.join(targetDir, ".claude", "CLAUDE.md");
610
552
  const agentsMd = await readFileIfExists(agentsMdPath);
611
553
  const rootClaudeMd = await readFileIfExists(rootClaudeMdPath);
612
554
  if (rootClaudeMd !== null) {
@@ -659,12 +601,12 @@ async function mergeAgentsMd(targetDir, globalContent, _source, options = { over
659
601
  };
660
602
  }
661
603
  async function writeAgentsMd(targetDir, content) {
662
- const agentsMdPath = path5.join(targetDir, "AGENTS.md");
663
- await fs5.writeFile(agentsMdPath, content, "utf-8");
604
+ const agentsMdPath = path4.join(targetDir, "AGENTS.md");
605
+ await fs4.writeFile(agentsMdPath, content, "utf-8");
664
606
  }
665
607
  async function ensureClaudeMd(targetDir, existingLocation) {
666
- const rootPath = path5.join(targetDir, "CLAUDE.md");
667
- const dotClaudePath = path5.join(targetDir, ".claude", "CLAUDE.md");
608
+ const rootPath = path4.join(targetDir, "CLAUDE.md");
609
+ const dotClaudePath = path4.join(targetDir, ".claude", "CLAUDE.md");
668
610
  const rootReference = "@AGENTS.md";
669
611
  const dotClaudeReference = "@../AGENTS.md";
670
612
  if (existingLocation === "root") {
@@ -673,7 +615,7 @@ async function ensureClaudeMd(targetDir, existingLocation) {
673
615
  if (existingContent.includes(rootReference)) {
674
616
  return { created: false, updated: false, location: "root", contentMerged: false };
675
617
  }
676
- await fs5.writeFile(rootPath, `${rootReference}
618
+ await fs4.writeFile(rootPath, `${rootReference}
677
619
  `, "utf-8");
678
620
  return { created: false, updated: true, location: "root", contentMerged: true };
679
621
  }
@@ -684,13 +626,13 @@ async function ensureClaudeMd(targetDir, existingLocation) {
684
626
  if (existingContent.includes(dotClaudeReference)) {
685
627
  return { created: false, updated: false, location: "dotclaude", contentMerged: false };
686
628
  }
687
- await fs5.writeFile(dotClaudePath, `${dotClaudeReference}
629
+ await fs4.writeFile(dotClaudePath, `${dotClaudeReference}
688
630
  `, "utf-8");
689
631
  return { created: false, updated: true, location: "dotclaude", contentMerged: true };
690
632
  }
691
633
  }
692
- await fs5.mkdir(path5.dirname(dotClaudePath), { recursive: true });
693
- await fs5.writeFile(dotClaudePath, `${dotClaudeReference}
634
+ await fs4.mkdir(path4.dirname(dotClaudePath), { recursive: true });
635
+ await fs4.writeFile(dotClaudePath, `${dotClaudeReference}
694
636
  `, "utf-8");
695
637
  return { created: true, updated: false, location: "dotclaude", contentMerged: false };
696
638
  }
@@ -734,7 +676,7 @@ function getTargetConfig(target) {
734
676
 
735
677
  // src/core/sync.ts
736
678
  async function sync(targetDir, resolvedSource, options = { override: false, targets: ["claude"] }) {
737
- const globalContent = await fs6.readFile(resolvedSource.agentsMdPath, "utf-8");
679
+ const globalContent = await fs5.readFile(resolvedSource.agentsMdPath, "utf-8");
738
680
  const mergeResult = await mergeAgentsMd(targetDir, globalContent, resolvedSource.source, {
739
681
  override: options.override
740
682
  });
@@ -747,9 +689,9 @@ async function sync(targetDir, resolvedSource, options = { override: false, targ
747
689
  const skillNames = skillDirs.map((d) => d.replace(/\/$/, ""));
748
690
  const validationErrors = [];
749
691
  for (const skillName of skillNames) {
750
- const skillMdPath = path6.join(resolvedSource.skillsPath, skillName, "SKILL.md");
692
+ const skillMdPath = path5.join(resolvedSource.skillsPath, skillName, "SKILL.md");
751
693
  try {
752
- const content = await fs6.readFile(skillMdPath, "utf-8");
694
+ const content = await fs5.readFile(skillMdPath, "utf-8");
753
695
  const error = validateSkillFrontmatter(content, skillName, skillMdPath);
754
696
  if (error) {
755
697
  validationErrors.push(error);
@@ -814,32 +756,32 @@ async function sync(targetDir, resolvedSource, options = { override: false, targ
814
756
  };
815
757
  }
816
758
  async function syncSkillsToTarget(targetDir, sourceSkillsPath, skillNames, config) {
817
- const targetSkillsPath = path6.join(targetDir, config.dir, "skills");
759
+ const targetSkillsPath = path5.join(targetDir, config.dir, "skills");
818
760
  let copied = 0;
819
761
  for (const skillName of skillNames) {
820
- const sourceDir = path6.join(sourceSkillsPath, skillName);
821
- const targetSkillDir = path6.join(targetSkillsPath, skillName);
762
+ const sourceDir = path5.join(sourceSkillsPath, skillName);
763
+ const targetSkillDir = path5.join(targetSkillsPath, skillName);
822
764
  const filesCopied = await copySkillDirectory(sourceDir, targetSkillDir);
823
765
  copied += filesCopied;
824
766
  }
825
767
  return copied;
826
768
  }
827
769
  async function copySkillDirectory(sourceDir, targetDir) {
828
- await fs6.mkdir(targetDir, { recursive: true });
829
- const entries = await fs6.readdir(sourceDir, { withFileTypes: true });
770
+ await fs5.mkdir(targetDir, { recursive: true });
771
+ const entries = await fs5.readdir(sourceDir, { withFileTypes: true });
830
772
  let copied = 0;
831
773
  for (const entry of entries) {
832
- const sourcePath = path6.join(sourceDir, entry.name);
833
- const targetPath = path6.join(targetDir, entry.name);
774
+ const sourcePath = path5.join(sourceDir, entry.name);
775
+ const targetPath = path5.join(targetDir, entry.name);
834
776
  if (entry.isDirectory()) {
835
777
  copied += await copySkillDirectory(sourcePath, targetPath);
836
778
  } else if (entry.name === "SKILL.md") {
837
- const content = await fs6.readFile(sourcePath, "utf-8");
779
+ const content = await fs5.readFile(sourcePath, "utf-8");
838
780
  const contentWithMetadata = addManagedMetadata(content);
839
- await fs6.writeFile(targetPath, contentWithMetadata, "utf-8");
781
+ await fs5.writeFile(targetPath, contentWithMetadata, "utf-8");
840
782
  copied++;
841
783
  } else {
842
- await fs6.copyFile(sourcePath, targetPath);
784
+ await fs5.copyFile(sourcePath, targetPath);
843
785
  copied++;
844
786
  }
845
787
  }
@@ -859,11 +801,11 @@ async function ensureInstructionsMd(targetDir, config, existingLocation) {
859
801
  }
860
802
  async function getSyncStatus(targetDir) {
861
803
  const lockfile = await readLockfile(targetDir);
862
- const agentsMdPath = path6.join(targetDir, "AGENTS.md");
863
- const skillsPath = path6.join(targetDir, ".claude", "skills");
804
+ const agentsMdPath = path5.join(targetDir, "AGENTS.md");
805
+ const skillsPath = path5.join(targetDir, ".claude", "skills");
864
806
  const [agentsMdExists, skillsExist] = await Promise.all([
865
- fs6.access(agentsMdPath).then(() => true).catch(() => false),
866
- fs6.access(skillsPath).then(() => true).catch(() => false)
807
+ fs5.access(agentsMdPath).then(() => true).catch(() => false),
808
+ fs5.access(skillsPath).then(() => true).catch(() => false)
867
809
  ]);
868
810
  return {
869
811
  hasSynced: lockfile !== null,
@@ -881,15 +823,15 @@ async function deleteOrphanedSkills(targetDir, orphanedSkills, targets, previous
881
823
  for (const skillName of orphanedSkills) {
882
824
  let wasDeleted = false;
883
825
  for (const target of targets) {
884
- const skillDir = path6.join(targetDir, `.${target}`, "skills", skillName);
826
+ const skillDir = path5.join(targetDir, `.${target}`, "skills", skillName);
885
827
  try {
886
- await fs6.access(skillDir);
828
+ await fs5.access(skillDir);
887
829
  } catch {
888
830
  continue;
889
831
  }
890
- const skillMdPath = path6.join(skillDir, "SKILL.md");
832
+ const skillMdPath = path5.join(skillDir, "SKILL.md");
891
833
  try {
892
- const content = await fs6.readFile(skillMdPath, "utf-8");
834
+ const content = await fs5.readFile(skillMdPath, "utf-8");
893
835
  const { isManaged, hasManualChanges } = await import("./skill-metadata-XANK6RZP.js");
894
836
  if (!isManaged(content)) {
895
837
  if (!skipped.includes(skillName)) {
@@ -911,7 +853,7 @@ async function deleteOrphanedSkills(targetDir, orphanedSkills, targets, previous
911
853
  }
912
854
  continue;
913
855
  }
914
- await fs6.rm(skillDir, { recursive: true, force: true });
856
+ await fs5.rm(skillDir, { recursive: true, force: true });
915
857
  wasDeleted = true;
916
858
  }
917
859
  if (wasDeleted && !deleted.includes(skillName)) {
@@ -922,13 +864,13 @@ async function deleteOrphanedSkills(targetDir, orphanedSkills, targets, previous
922
864
  }
923
865
 
924
866
  // src/commands/shared.ts
925
- import * as path12 from "path";
867
+ import * as path11 from "path";
926
868
  import * as prompts3 from "@clack/prompts";
927
869
  import pc5 from "picocolors";
928
870
 
929
871
  // src/core/hooks.ts
930
- import * as fs7 from "fs/promises";
931
- import * as path7 from "path";
872
+ import * as fs6 from "fs/promises";
873
+ import * as path6 from "path";
932
874
  var DEFAULT_CLI_NAME = "agent-conf";
933
875
  var DEFAULT_CONFIG_DIR = ".agent-conf";
934
876
  var DEFAULT_LOCKFILE_NAME = "lockfile.json";
@@ -994,13 +936,13 @@ function getHookConfig(config) {
994
936
  }
995
937
  async function installPreCommitHook(targetDir, config) {
996
938
  const hookConfig = getHookConfig(config);
997
- const hooksDir = path7.join(targetDir, ".git", "hooks");
998
- const hookPath = path7.join(hooksDir, "pre-commit");
939
+ const hooksDir = path6.join(targetDir, ".git", "hooks");
940
+ const hookPath = path6.join(hooksDir, "pre-commit");
999
941
  const hookContent = generatePreCommitHook(hookConfig);
1000
- await fs7.mkdir(hooksDir, { recursive: true });
942
+ await fs6.mkdir(hooksDir, { recursive: true });
1001
943
  let existingContent = null;
1002
944
  try {
1003
- existingContent = await fs7.readFile(hookPath, "utf-8");
945
+ existingContent = await fs6.readFile(hookPath, "utf-8");
1004
946
  } catch {
1005
947
  }
1006
948
  if (existingContent !== null) {
@@ -1021,7 +963,7 @@ async function installPreCommitHook(targetDir, config) {
1021
963
  wasUpdated: false
1022
964
  };
1023
965
  }
1024
- await fs7.writeFile(hookPath, hookContent, { mode: 493 });
966
+ await fs6.writeFile(hookPath, hookContent, { mode: 493 });
1025
967
  return {
1026
968
  installed: true,
1027
969
  path: hookPath,
@@ -1029,7 +971,7 @@ async function installPreCommitHook(targetDir, config) {
1029
971
  wasUpdated: true
1030
972
  };
1031
973
  }
1032
- await fs7.writeFile(hookPath, hookContent, { mode: 493 });
974
+ await fs6.writeFile(hookPath, hookContent, { mode: 493 });
1033
975
  return {
1034
976
  installed: true,
1035
977
  path: hookPath,
@@ -1039,14 +981,14 @@ async function installPreCommitHook(targetDir, config) {
1039
981
  }
1040
982
 
1041
983
  // src/core/source.ts
1042
- import * as fs8 from "fs/promises";
1043
- import * as path8 from "path";
984
+ import * as fs7 from "fs/promises";
985
+ import * as path7 from "path";
1044
986
  import { simpleGit } from "simple-git";
1045
987
  var DEFAULT_REF = "master";
1046
988
  async function resolveLocalSource(options = {}) {
1047
989
  let basePath;
1048
990
  if (options.path) {
1049
- basePath = path8.resolve(options.path);
991
+ basePath = path7.resolve(options.path);
1050
992
  } else {
1051
993
  basePath = await findCanonicalRepo(process.cwd());
1052
994
  }
@@ -1066,8 +1008,8 @@ async function resolveLocalSource(options = {}) {
1066
1008
  return {
1067
1009
  source,
1068
1010
  basePath,
1069
- agentsMdPath: path8.join(basePath, "instructions", "AGENTS.md"),
1070
- skillsPath: path8.join(basePath, "skills")
1011
+ agentsMdPath: path7.join(basePath, "instructions", "AGENTS.md"),
1012
+ skillsPath: path7.join(basePath, "skills")
1071
1013
  };
1072
1014
  }
1073
1015
  async function resolveGithubSource(options, tempDir) {
@@ -1087,24 +1029,24 @@ async function resolveGithubSource(options, tempDir) {
1087
1029
  return {
1088
1030
  source,
1089
1031
  basePath: tempDir,
1090
- agentsMdPath: path8.join(tempDir, "instructions", "AGENTS.md"),
1091
- skillsPath: path8.join(tempDir, "skills")
1032
+ agentsMdPath: path7.join(tempDir, "instructions", "AGENTS.md"),
1033
+ skillsPath: path7.join(tempDir, "skills")
1092
1034
  };
1093
1035
  }
1094
1036
  async function findCanonicalRepo(startDir) {
1095
- let currentDir = path8.resolve(startDir);
1096
- const root = path8.parse(currentDir).root;
1037
+ let currentDir = path7.resolve(startDir);
1038
+ const root = path7.parse(currentDir).root;
1097
1039
  let checkDir = currentDir;
1098
1040
  while (checkDir !== root) {
1099
1041
  if (await isCanonicalRepo(checkDir)) {
1100
1042
  return checkDir;
1101
1043
  }
1102
- checkDir = path8.dirname(checkDir);
1044
+ checkDir = path7.dirname(checkDir);
1103
1045
  }
1104
- currentDir = path8.resolve(startDir);
1046
+ currentDir = path7.resolve(startDir);
1105
1047
  while (currentDir !== root) {
1106
- const parentDir = path8.dirname(currentDir);
1107
- const siblingCanonicalRepo = path8.join(parentDir, "agent-conf");
1048
+ const parentDir = path7.dirname(currentDir);
1049
+ const siblingCanonicalRepo = path7.join(parentDir, "agent-conf");
1108
1050
  if (await isCanonicalRepo(siblingCanonicalRepo)) {
1109
1051
  return siblingCanonicalRepo;
1110
1052
  }
@@ -1116,15 +1058,15 @@ async function findCanonicalRepo(startDir) {
1116
1058
  }
1117
1059
  async function isCanonicalRepo(dir) {
1118
1060
  try {
1119
- const stat4 = await fs8.stat(dir).catch(() => null);
1061
+ const stat4 = await fs7.stat(dir).catch(() => null);
1120
1062
  if (!stat4?.isDirectory()) {
1121
1063
  return false;
1122
1064
  }
1123
- const instructionsPath = path8.join(dir, "instructions", "AGENTS.md");
1124
- const skillsPath = path8.join(dir, "skills");
1065
+ const instructionsPath = path7.join(dir, "instructions", "AGENTS.md");
1066
+ const skillsPath = path7.join(dir, "skills");
1125
1067
  const [instructionsExists, skillsExists] = await Promise.all([
1126
- fs8.access(instructionsPath).then(() => true).catch(() => false),
1127
- fs8.access(skillsPath).then(() => true).catch(() => false)
1068
+ fs7.access(instructionsPath).then(() => true).catch(() => false),
1069
+ fs7.access(skillsPath).then(() => true).catch(() => false)
1128
1070
  ]);
1129
1071
  if (!instructionsExists || !skillsExists) {
1130
1072
  return false;
@@ -1146,11 +1088,11 @@ async function isCanonicalRepo(dir) {
1146
1088
  }
1147
1089
  }
1148
1090
  async function validateCanonicalRepo(basePath) {
1149
- const agentsMdPath = path8.join(basePath, "instructions", "AGENTS.md");
1150
- const skillsPath = path8.join(basePath, "skills");
1091
+ const agentsMdPath = path7.join(basePath, "instructions", "AGENTS.md");
1092
+ const skillsPath = path7.join(basePath, "skills");
1151
1093
  const [agentsMdExists, skillsExists] = await Promise.all([
1152
- fs8.access(agentsMdPath).then(() => true).catch(() => false),
1153
- fs8.access(skillsPath).then(() => true).catch(() => false)
1094
+ fs7.access(agentsMdPath).then(() => true).catch(() => false),
1095
+ fs7.access(skillsPath).then(() => true).catch(() => false)
1154
1096
  ]);
1155
1097
  if (!agentsMdExists) {
1156
1098
  throw new Error(`Invalid canonical repository: missing instructions/AGENTS.md at ${basePath}`);
@@ -1269,8 +1211,8 @@ function compareVersions(a, b) {
1269
1211
  }
1270
1212
 
1271
1213
  // src/core/workflows.ts
1272
- import * as fs9 from "fs/promises";
1273
- import * as path9 from "path";
1214
+ import * as fs8 from "fs/promises";
1215
+ import * as path8 from "path";
1274
1216
  var DEFAULT_CLI_NAME2 = "agent-conf";
1275
1217
  var WORKFLOWS_DIR = ".github/workflows";
1276
1218
  function getWorkflowConfig(sourceRepo, config) {
@@ -1299,10 +1241,10 @@ function getWorkflowFiles(config) {
1299
1241
  ];
1300
1242
  }
1301
1243
  function getWorkflowsDir(repoRoot) {
1302
- return path9.join(repoRoot, WORKFLOWS_DIR);
1244
+ return path8.join(repoRoot, WORKFLOWS_DIR);
1303
1245
  }
1304
1246
  function getWorkflowPath(repoRoot, filename) {
1305
- return path9.join(repoRoot, WORKFLOWS_DIR, filename);
1247
+ return path8.join(repoRoot, WORKFLOWS_DIR, filename);
1306
1248
  }
1307
1249
  function generateSyncWorkflow(versionRef, config) {
1308
1250
  const { sourceRepo, cliName, secretName } = config;
@@ -1392,13 +1334,13 @@ function generateWorkflow(workflow, versionRef, config) {
1392
1334
  }
1393
1335
  async function ensureWorkflowsDir(repoRoot) {
1394
1336
  const dir = getWorkflowsDir(repoRoot);
1395
- await fs9.mkdir(dir, { recursive: true });
1337
+ await fs8.mkdir(dir, { recursive: true });
1396
1338
  }
1397
1339
  async function writeWorkflow(repoRoot, workflow, versionRef, config) {
1398
1340
  await ensureWorkflowsDir(repoRoot);
1399
1341
  const filePath = getWorkflowPath(repoRoot, workflow.filename);
1400
1342
  const content = generateWorkflow(workflow, versionRef, config);
1401
- await fs9.writeFile(filePath, content, "utf-8");
1343
+ await fs8.writeFile(filePath, content, "utf-8");
1402
1344
  }
1403
1345
  async function syncWorkflows(repoRoot, versionRef, sourceRepo, resolvedConfig) {
1404
1346
  const config = getWorkflowConfig(sourceRepo, resolvedConfig);
@@ -1413,7 +1355,7 @@ async function syncWorkflows(repoRoot, versionRef, sourceRepo, resolvedConfig) {
1413
1355
  const expectedContent = generateWorkflow(workflow, versionRef, config);
1414
1356
  let existingContent = null;
1415
1357
  try {
1416
- existingContent = await fs9.readFile(filePath, "utf-8");
1358
+ existingContent = await fs8.readFile(filePath, "utf-8");
1417
1359
  } catch {
1418
1360
  }
1419
1361
  if (existingContent === null) {
@@ -1430,15 +1372,15 @@ async function syncWorkflows(repoRoot, versionRef, sourceRepo, resolvedConfig) {
1430
1372
  }
1431
1373
 
1432
1374
  // src/utils/fs.ts
1433
- import * as fs10 from "fs/promises";
1434
- import * as os3 from "os";
1435
- import * as path10 from "path";
1375
+ import * as fs9 from "fs/promises";
1376
+ import * as os2 from "os";
1377
+ import * as path9 from "path";
1436
1378
  async function ensureDir(dirPath) {
1437
- await fs10.mkdir(dirPath, { recursive: true });
1379
+ await fs9.mkdir(dirPath, { recursive: true });
1438
1380
  }
1439
1381
  async function fileExists(filePath) {
1440
1382
  try {
1441
- await fs10.access(filePath);
1383
+ await fs9.access(filePath);
1442
1384
  return true;
1443
1385
  } catch {
1444
1386
  return false;
@@ -1446,36 +1388,36 @@ async function fileExists(filePath) {
1446
1388
  }
1447
1389
  async function directoryExists(dirPath) {
1448
1390
  try {
1449
- const stat4 = await fs10.stat(dirPath);
1391
+ const stat4 = await fs9.stat(dirPath);
1450
1392
  return stat4.isDirectory();
1451
1393
  } catch {
1452
1394
  return false;
1453
1395
  }
1454
1396
  }
1455
1397
  async function createTempDir(prefix = "agent-conf-") {
1456
- const tmpDir = os3.tmpdir();
1457
- return fs10.mkdtemp(path10.join(tmpDir, prefix));
1398
+ const tmpDir = os2.tmpdir();
1399
+ return fs9.mkdtemp(path9.join(tmpDir, prefix));
1458
1400
  }
1459
1401
  async function removeTempDir(dirPath) {
1460
1402
  try {
1461
- await fs10.rm(dirPath, { recursive: true, force: true });
1403
+ await fs9.rm(dirPath, { recursive: true, force: true });
1462
1404
  } catch {
1463
1405
  }
1464
1406
  }
1465
1407
  function resolvePath(inputPath) {
1466
1408
  if (inputPath.startsWith("~")) {
1467
- return path10.join(os3.homedir(), inputPath.slice(1));
1409
+ return path9.join(os2.homedir(), inputPath.slice(1));
1468
1410
  }
1469
- return path10.resolve(inputPath);
1411
+ return path9.resolve(inputPath);
1470
1412
  }
1471
1413
 
1472
1414
  // src/utils/git.ts
1473
- import * as fs11 from "fs/promises";
1474
- import * as path11 from "path";
1415
+ import * as fs10 from "fs/promises";
1416
+ import * as path10 from "path";
1475
1417
  import { simpleGit as simpleGit2 } from "simple-git";
1476
1418
  async function directoryExistsForGit(dir) {
1477
1419
  try {
1478
- const stat4 = await fs11.stat(dir);
1420
+ const stat4 = await fs10.stat(dir);
1479
1421
  return stat4.isDirectory();
1480
1422
  } catch {
1481
1423
  return false;
@@ -1502,7 +1444,7 @@ async function getGitProjectName(dir) {
1502
1444
  if (!gitRoot) {
1503
1445
  return null;
1504
1446
  }
1505
- return path11.basename(gitRoot);
1447
+ return path10.basename(gitRoot);
1506
1448
  }
1507
1449
  async function isGitRoot(dir) {
1508
1450
  if (!await directoryExistsForGit(dir)) {
@@ -1513,11 +1455,11 @@ async function isGitRoot(dir) {
1513
1455
  return false;
1514
1456
  }
1515
1457
  try {
1516
- const realDir = await fs11.realpath(dir);
1517
- const realGitRoot = await fs11.realpath(gitRoot);
1458
+ const realDir = await fs10.realpath(dir);
1459
+ const realGitRoot = await fs10.realpath(gitRoot);
1518
1460
  return realDir === realGitRoot;
1519
1461
  } catch {
1520
- return path11.resolve(dir) === path11.resolve(gitRoot);
1462
+ return path10.resolve(dir) === path10.resolve(gitRoot);
1521
1463
  }
1522
1464
  }
1523
1465
  async function getGitOrganization(dir) {
@@ -1574,7 +1516,7 @@ async function resolveTargetDirectory() {
1574
1516
  }
1575
1517
  return gitRoot;
1576
1518
  }
1577
- async function resolveVersion(options, status, commandName, repo) {
1519
+ async function resolveVersion(options, status, _commandName, repo) {
1578
1520
  const logger = createLogger();
1579
1521
  if (options.local !== void 0) {
1580
1522
  return {
@@ -1600,7 +1542,11 @@ async function resolveVersion(options, status, commandName, repo) {
1600
1542
  releaseInfo: null
1601
1543
  };
1602
1544
  }
1603
- if (commandName === "sync" && status.lockfile?.pinned_version) {
1545
+ if (options.pinned) {
1546
+ if (!status.lockfile?.pinned_version) {
1547
+ logger.error("Cannot use --pinned: no version pinned in lockfile.");
1548
+ process.exit(1);
1549
+ }
1604
1550
  const version = status.lockfile.pinned_version;
1605
1551
  return {
1606
1552
  ref: formatTag(version),
@@ -1822,7 +1768,7 @@ async function performSync(options) {
1822
1768
  console.log();
1823
1769
  console.log(pc5.bold("Sync complete:"));
1824
1770
  console.log();
1825
- const agentsMdPath = formatPath(path12.join(targetDir, "AGENTS.md"));
1771
+ const agentsMdPath = formatPath(path11.join(targetDir, "AGENTS.md"));
1826
1772
  if (result.agentsMd.merged) {
1827
1773
  const label = context.commandName === "sync" ? "(updated)" : "(merged)";
1828
1774
  console.log(` ${pc5.green("+")} ${agentsMdPath} ${pc5.dim(label)}`);
@@ -1832,7 +1778,7 @@ async function performSync(options) {
1832
1778
  for (const targetResult of result.targets) {
1833
1779
  const config = getTargetConfig(targetResult.target);
1834
1780
  if (config.instructionsFile) {
1835
- const instructionsPath = targetResult.instructionsMd.location === "root" ? formatPath(path12.join(targetDir, config.instructionsFile)) : formatPath(path12.join(targetDir, config.dir, config.instructionsFile));
1781
+ const instructionsPath = targetResult.instructionsMd.location === "root" ? formatPath(path11.join(targetDir, config.instructionsFile)) : formatPath(path11.join(targetDir, config.dir, config.instructionsFile));
1836
1782
  if (targetResult.instructionsMd.created) {
1837
1783
  console.log(` ${pc5.green("+")} ${instructionsPath} ${pc5.dim("(created)")}`);
1838
1784
  } else if (targetResult.instructionsMd.updated) {
@@ -1842,13 +1788,13 @@ async function performSync(options) {
1842
1788
  console.log(` ${pc5.dim("-")} ${instructionsPath} ${pc5.dim("(unchanged)")}`);
1843
1789
  }
1844
1790
  }
1845
- const skillsPath = formatPath(path12.join(targetDir, config.dir, "skills"));
1791
+ const skillsPath = formatPath(path11.join(targetDir, config.dir, "skills"));
1846
1792
  console.log(
1847
1793
  ` ${pc5.green("+")} ${skillsPath}/ ${pc5.dim(`(${result.skills.synced.length} skills, ${targetResult.skills.copied} files)`)}`
1848
1794
  );
1849
1795
  if (orphanResult.deleted.length > 0) {
1850
1796
  for (const skill of orphanResult.deleted) {
1851
- const orphanPath = formatPath(path12.join(targetDir, config.dir, "skills", skill));
1797
+ const orphanPath = formatPath(path11.join(targetDir, config.dir, "skills", skill));
1852
1798
  console.log(
1853
1799
  ` ${pc5.red("-")} ${orphanPath}/ ${pc5.dim("(removed - no longer in source)")}`
1854
1800
  );
@@ -1856,28 +1802,28 @@ async function performSync(options) {
1856
1802
  }
1857
1803
  if (orphanResult.skipped.length > 0) {
1858
1804
  for (const skill of orphanResult.skipped) {
1859
- const orphanPath = formatPath(path12.join(targetDir, config.dir, "skills", skill));
1805
+ const orphanPath = formatPath(path11.join(targetDir, config.dir, "skills", skill));
1860
1806
  console.log(` ${pc5.yellow("!")} ${orphanPath}/ ${pc5.dim("(orphaned but skipped)")}`);
1861
1807
  }
1862
1808
  }
1863
1809
  }
1864
1810
  if (workflowResult) {
1865
1811
  for (const filename of workflowResult.created) {
1866
- const workflowPath = formatPath(path12.join(targetDir, ".github/workflows", filename));
1812
+ const workflowPath = formatPath(path11.join(targetDir, ".github/workflows", filename));
1867
1813
  console.log(` ${pc5.green("+")} ${workflowPath} ${pc5.dim("(created)")}`);
1868
1814
  }
1869
1815
  for (const filename of workflowResult.updated) {
1870
- const workflowPath = formatPath(path12.join(targetDir, ".github/workflows", filename));
1816
+ const workflowPath = formatPath(path11.join(targetDir, ".github/workflows", filename));
1871
1817
  console.log(` ${pc5.yellow("~")} ${workflowPath} ${pc5.dim("(updated)")}`);
1872
1818
  }
1873
1819
  for (const filename of workflowResult.unchanged) {
1874
- const workflowPath = formatPath(path12.join(targetDir, ".github/workflows", filename));
1820
+ const workflowPath = formatPath(path11.join(targetDir, ".github/workflows", filename));
1875
1821
  console.log(` ${pc5.dim("-")} ${workflowPath} ${pc5.dim("(unchanged)")}`);
1876
1822
  }
1877
1823
  }
1878
- const lockfilePath = formatPath(path12.join(targetDir, ".agent-conf", "agent-conf.lock"));
1824
+ const lockfilePath = formatPath(path11.join(targetDir, ".agent-conf", "agent-conf.lock"));
1879
1825
  console.log(` ${pc5.green("+")} ${lockfilePath}`);
1880
- const hookPath = formatPath(path12.join(targetDir, ".git/hooks/pre-commit"));
1826
+ const hookPath = formatPath(path11.join(targetDir, ".git/hooks/pre-commit"));
1881
1827
  if (hookResult.installed) {
1882
1828
  if (hookResult.alreadyExisted && !hookResult.wasUpdated) {
1883
1829
  console.log(` ${pc5.dim("-")} ${hookPath} ${pc5.dim("(unchanged)")}`);
@@ -1947,8 +1893,8 @@ async function initCommand(options) {
1947
1893
  }
1948
1894
 
1949
1895
  // src/commands/init-canonical-repo.ts
1950
- import * as fs12 from "fs/promises";
1951
- import * as path13 from "path";
1896
+ import * as fs11 from "fs/promises";
1897
+ import * as path12 from "path";
1952
1898
  import * as prompts5 from "@clack/prompts";
1953
1899
  import pc7 from "picocolors";
1954
1900
  import { stringify as stringifyYaml } from "yaml";
@@ -2052,9 +1998,6 @@ function generateSyncWorkflow2(repoFullName, prefix) {
2052
1998
  #
2053
1999
  # Downstream repos will reference this workflow like:
2054
2000
  # uses: ${repoFullName}/.github/workflows/sync-reusable.yml@v1.0.0
2055
- #
2056
- # SETUP REQUIRED: Update the CLI installation step below with your installation method.
2057
- # See https://github.com/julian-pani/agent-conf/blob/master/cli/docs/CANONICAL_REPOSITORY_SETUP.md for detailed instructions.
2058
2001
 
2059
2002
  name: Sync Reusable
2060
2003
 
@@ -2090,13 +2033,7 @@ jobs:
2090
2033
  node-version: '20'
2091
2034
 
2092
2035
  - name: Install agent-conf CLI
2093
- run: |
2094
- # TODO: Update with your CLI installation method
2095
- # Example using git clone (replace with your CLI repository):
2096
- # git clone --depth 1 git@github.com:your-org/agent-conf.git /tmp/agent-conf \\
2097
- # && /tmp/agent-conf/cli/scripts/install_local.sh
2098
- echo "ERROR: CLI installation not configured. See https://github.com/julian-pani/agent-conf/blob/master/cli/docs/CANONICAL_REPOSITORY_SETUP.md"
2099
- exit 1
2036
+ run: npm install -g agent-conf
2100
2037
 
2101
2038
  - name: Run sync
2102
2039
  run: |
@@ -2111,9 +2048,6 @@ function generateCheckWorkflow2(repoFullName, prefix) {
2111
2048
  #
2112
2049
  # Downstream repos will reference this workflow like:
2113
2050
  # uses: ${repoFullName}/.github/workflows/check-reusable.yml@v1.0.0
2114
- #
2115
- # SETUP REQUIRED: Update the CLI installation step below with your installation method.
2116
- # See https://github.com/julian-pani/agent-conf/blob/master/cli/docs/CANONICAL_REPOSITORY_SETUP.md for detailed instructions.
2117
2051
 
2118
2052
  name: Check Reusable
2119
2053
 
@@ -2139,13 +2073,7 @@ jobs:
2139
2073
  node-version: '20'
2140
2074
 
2141
2075
  - name: Install agent-conf CLI
2142
- run: |
2143
- # TODO: Update with your CLI installation method
2144
- # Example using git clone (replace with your CLI repository):
2145
- # git clone --depth 1 git@github.com:your-org/agent-conf.git /tmp/agent-conf \\
2146
- # && /tmp/agent-conf/cli/scripts/install_local.sh
2147
- echo "ERROR: CLI installation not configured. See https://github.com/julian-pani/agent-conf/blob/master/cli/docs/CANONICAL_REPOSITORY_SETUP.md"
2148
- exit 1
2076
+ run: npm install -g agent-conf
2149
2077
 
2150
2078
  - name: Check file integrity
2151
2079
  run: |
@@ -2156,8 +2084,8 @@ async function initCanonicalRepoCommand(options) {
2156
2084
  const logger = createLogger();
2157
2085
  console.log();
2158
2086
  prompts5.intro(pc7.bold("agent-conf init-canonical-repo"));
2159
- const targetDir = options.dir ? path13.resolve(options.dir) : process.cwd();
2160
- const dirName = path13.basename(targetDir);
2087
+ const targetDir = options.dir ? path12.resolve(options.dir) : process.cwd();
2088
+ const dirName = path12.basename(targetDir);
2161
2089
  const cwd = process.cwd();
2162
2090
  let isAtGitRoot = await isGitRoot(targetDir);
2163
2091
  let gitProjectName = await getGitProjectName(targetDir);
@@ -2166,7 +2094,7 @@ async function initCanonicalRepoCommand(options) {
2166
2094
  const cwdIsGitRoot = await isGitRoot(cwd);
2167
2095
  const cwdGitProjectName = await getGitProjectName(cwd);
2168
2096
  const cwdGitOrganization = await getGitOrganization(cwd);
2169
- if (cwdIsGitRoot && path13.resolve(targetDir) === path13.resolve(cwd)) {
2097
+ if (cwdIsGitRoot && path12.resolve(targetDir) === path12.resolve(cwd)) {
2170
2098
  isAtGitRoot = true;
2171
2099
  gitProjectName = cwdGitProjectName;
2172
2100
  gitOrganization = cwdGitOrganization;
@@ -2185,7 +2113,7 @@ async function initCanonicalRepoCommand(options) {
2185
2113
  }
2186
2114
  const dirExists = await directoryExists(targetDir);
2187
2115
  if (dirExists) {
2188
- const configExists = await fileExists(path13.join(targetDir, "agent-conf.yaml"));
2116
+ const configExists = await fileExists(path12.join(targetDir, "agent-conf.yaml"));
2189
2117
  if (configExists && !options.yes) {
2190
2118
  const shouldContinue = await prompts5.confirm({
2191
2119
  message: "This directory already has an agent-conf.yaml. Overwrite?",
@@ -2267,34 +2195,34 @@ async function initCanonicalRepoCommand(options) {
2267
2195
  spinner.start();
2268
2196
  try {
2269
2197
  await ensureDir(resolvedOptions.targetDir);
2270
- const instructionsDir = path13.join(resolvedOptions.targetDir, "instructions");
2271
- const skillsDir = path13.join(resolvedOptions.targetDir, "skills");
2272
- const workflowsDir = path13.join(resolvedOptions.targetDir, ".github", "workflows");
2198
+ const instructionsDir = path12.join(resolvedOptions.targetDir, "instructions");
2199
+ const skillsDir = path12.join(resolvedOptions.targetDir, "skills");
2200
+ const workflowsDir = path12.join(resolvedOptions.targetDir, ".github", "workflows");
2273
2201
  await ensureDir(instructionsDir);
2274
2202
  await ensureDir(skillsDir);
2275
2203
  await ensureDir(workflowsDir);
2276
- const configPath = path13.join(resolvedOptions.targetDir, "agent-conf.yaml");
2277
- await fs12.writeFile(configPath, generateConfigYaml(resolvedOptions), "utf-8");
2278
- const agentsMdPath = path13.join(instructionsDir, "AGENTS.md");
2279
- await fs12.writeFile(agentsMdPath, generateAgentsMd(resolvedOptions), "utf-8");
2204
+ const configPath = path12.join(resolvedOptions.targetDir, "agent-conf.yaml");
2205
+ await fs11.writeFile(configPath, generateConfigYaml(resolvedOptions), "utf-8");
2206
+ const agentsMdPath = path12.join(instructionsDir, "AGENTS.md");
2207
+ await fs11.writeFile(agentsMdPath, generateAgentsMd(resolvedOptions), "utf-8");
2280
2208
  if (resolvedOptions.includeExamples) {
2281
- const exampleSkillDir = path13.join(skillsDir, "example-skill");
2282
- const referencesDir = path13.join(exampleSkillDir, "references");
2209
+ const exampleSkillDir = path12.join(skillsDir, "example-skill");
2210
+ const referencesDir = path12.join(exampleSkillDir, "references");
2283
2211
  await ensureDir(referencesDir);
2284
- const skillMdPath = path13.join(exampleSkillDir, "SKILL.md");
2285
- await fs12.writeFile(skillMdPath, generateExampleSkillMd(), "utf-8");
2286
- const gitkeepPath = path13.join(referencesDir, ".gitkeep");
2287
- await fs12.writeFile(gitkeepPath, "", "utf-8");
2212
+ const skillMdPath = path12.join(exampleSkillDir, "SKILL.md");
2213
+ await fs11.writeFile(skillMdPath, generateExampleSkillMd(), "utf-8");
2214
+ const gitkeepPath = path12.join(referencesDir, ".gitkeep");
2215
+ await fs11.writeFile(gitkeepPath, "", "utf-8");
2288
2216
  }
2289
- const syncWorkflowPath = path13.join(workflowsDir, "sync-reusable.yml");
2290
- const checkWorkflowPath = path13.join(workflowsDir, "check-reusable.yml");
2217
+ const syncWorkflowPath = path12.join(workflowsDir, "sync-reusable.yml");
2218
+ const checkWorkflowPath = path12.join(workflowsDir, "check-reusable.yml");
2291
2219
  const repoFullName = resolvedOptions.organization ? `${resolvedOptions.organization}/${resolvedOptions.name}` : resolvedOptions.name;
2292
- await fs12.writeFile(
2220
+ await fs11.writeFile(
2293
2221
  syncWorkflowPath,
2294
2222
  generateSyncWorkflow2(repoFullName, resolvedOptions.markerPrefix),
2295
2223
  "utf-8"
2296
2224
  );
2297
- await fs12.writeFile(
2225
+ await fs11.writeFile(
2298
2226
  checkWorkflowPath,
2299
2227
  generateCheckWorkflow2(repoFullName, resolvedOptions.markerPrefix),
2300
2228
  "utf-8"
@@ -2306,7 +2234,7 @@ async function initCanonicalRepoCommand(options) {
2306
2234
  console.log(` ${pc7.green("+")} ${formatPath(agentsMdPath)}`);
2307
2235
  if (resolvedOptions.includeExamples) {
2308
2236
  console.log(
2309
- ` ${pc7.green("+")} ${formatPath(path13.join(skillsDir, "example-skill/SKILL.md"))}`
2237
+ ` ${pc7.green("+")} ${formatPath(path12.join(skillsDir, "example-skill/SKILL.md"))}`
2310
2238
  );
2311
2239
  }
2312
2240
  console.log(` ${pc7.green("+")} ${formatPath(syncWorkflowPath)}`);
@@ -2321,13 +2249,13 @@ async function initCanonicalRepoCommand(options) {
2321
2249
  console.log(pc7.bold("Next steps:"));
2322
2250
  console.log(` 1. Edit ${pc7.cyan("instructions/AGENTS.md")} with your engineering standards`);
2323
2251
  console.log(` 2. Add skills to ${pc7.cyan("skills/")} directory`);
2252
+ console.log(` 3. Commit and push to create your canonical repository`);
2253
+ console.log();
2324
2254
  console.log(
2325
- ` 3. Update ${pc7.cyan(".github/workflows/")} files with your CLI installation method`
2255
+ pc7.dim(
2256
+ `See https://github.com/julian-pani/agent-conf/blob/master/cli/docs/CANONICAL_REPOSITORY_SETUP.md for detailed setup instructions.`
2257
+ )
2326
2258
  );
2327
- console.log(` (The workflow files will fail until you configure how to install the CLI)`);
2328
- console.log(` 4. Commit and push to create your canonical repository`);
2329
- console.log();
2330
- console.log(pc7.dim(`See https://github.com/julian-pani/agent-conf/blob/master/cli/docs/CANONICAL_REPOSITORY_SETUP.md for detailed setup instructions.`));
2331
2259
  prompts5.outro(pc7.green("Done!"));
2332
2260
  } catch (error) {
2333
2261
  spinner.fail("Failed to create canonical repository");
@@ -2337,7 +2265,7 @@ async function initCanonicalRepoCommand(options) {
2337
2265
  }
2338
2266
 
2339
2267
  // src/commands/status.ts
2340
- import * as path14 from "path";
2268
+ import * as path13 from "path";
2341
2269
  import pc8 from "picocolors";
2342
2270
  async function statusCommand(options = {}) {
2343
2271
  const targetDir = process.cwd();
@@ -2390,7 +2318,7 @@ async function statusCommand(options = {}) {
2390
2318
  }
2391
2319
  console.log();
2392
2320
  }
2393
- const lockfilePath = formatPath(path14.join(targetDir, ".agent-conf", "agent-conf.lock"));
2321
+ const lockfilePath = formatPath(path13.join(targetDir, ".agent-conf", "agent-conf.lock"));
2394
2322
  console.log(pc8.dim(`Lock file: ${lockfilePath}`));
2395
2323
  console.log(pc8.dim(`CLI version: ${lockfile.cli_version}`));
2396
2324
  console.log();
@@ -2403,6 +2331,14 @@ async function syncCommand(options) {
2403
2331
  const logger = createLogger();
2404
2332
  console.log();
2405
2333
  prompts6.intro(pc9.bold("agent-conf sync"));
2334
+ if (options.pinned && options.ref) {
2335
+ logger.error("Cannot use --pinned with --ref. Choose one.");
2336
+ process.exit(1);
2337
+ }
2338
+ if (options.pinned && options.local !== void 0) {
2339
+ logger.error("Cannot use --pinned with --local.");
2340
+ process.exit(1);
2341
+ }
2406
2342
  const targetDir = await resolveTargetDirectory();
2407
2343
  const targets = await parseAndValidateTargets(options.target);
2408
2344
  const status = await getSyncStatus(targetDir);
@@ -2416,6 +2352,36 @@ async function syncCommand(options) {
2416
2352
  sourceRepo = status.lockfile.source.repository;
2417
2353
  }
2418
2354
  const resolvedVersion = await resolveVersion(options, status, "sync", sourceRepo);
2355
+ if (!options.pinned && !options.ref && !options.local && status.lockfile?.pinned_version) {
2356
+ const currentVersion = status.lockfile.pinned_version;
2357
+ if (resolvedVersion.version) {
2358
+ const comparison = compareVersions(currentVersion, resolvedVersion.version);
2359
+ console.log();
2360
+ console.log(`Canonical source: ${pc9.cyan(sourceRepo)}`);
2361
+ console.log(`Latest release: ${pc9.cyan(resolvedVersion.version)}`);
2362
+ console.log(`Pinned version: ${pc9.cyan(currentVersion)}`);
2363
+ if (comparison >= 0) {
2364
+ console.log(` ${pc9.green("\u2713")} Up to date`);
2365
+ console.log();
2366
+ prompts6.outro(pc9.green("Already up to date!"));
2367
+ return;
2368
+ }
2369
+ console.log(
2370
+ ` ${pc9.yellow("\u2192")} Update available: ${currentVersion} \u2192 ${resolvedVersion.version}`
2371
+ );
2372
+ console.log();
2373
+ if (!options.yes) {
2374
+ const shouldUpdate = await prompts6.confirm({
2375
+ message: "Proceed with update?",
2376
+ initialValue: true
2377
+ });
2378
+ if (prompts6.isCancel(shouldUpdate) || !shouldUpdate) {
2379
+ prompts6.cancel("Sync cancelled");
2380
+ process.exit(0);
2381
+ }
2382
+ }
2383
+ }
2384
+ }
2419
2385
  if (options.ref && status.lockfile?.pinned_version) {
2420
2386
  const currentVersion = status.lockfile.pinned_version;
2421
2387
  if (resolvedVersion.version && currentVersion !== resolvedVersion.version) {
@@ -2445,176 +2411,29 @@ async function syncCommand(options) {
2445
2411
  });
2446
2412
  }
2447
2413
 
2448
- // src/commands/update.ts
2449
- import * as prompts7 from "@clack/prompts";
2450
- import pc10 from "picocolors";
2451
- function getRepositoryFromLockfile(status) {
2452
- if (!status.lockfile?.source) {
2453
- return void 0;
2454
- }
2455
- if (status.lockfile.source.type === "github") {
2456
- return status.lockfile.source.repository;
2457
- }
2458
- return void 0;
2459
- }
2460
- async function updateCommand(options) {
2461
- const logger = createLogger();
2462
- const currentCliVersion = getCliVersion();
2463
- console.log();
2464
- prompts7.intro(pc10.bold("agent-conf update"));
2465
- const cwd = process.cwd();
2466
- const gitRoot = await getGitRoot(cwd);
2467
- if (!gitRoot) {
2468
- logger.error("Not inside a git repository. Run this command from within a git repository.");
2469
- process.exit(1);
2470
- }
2471
- const status = await getSyncStatus(gitRoot);
2472
- const sourceRepository = getRepositoryFromLockfile(status);
2473
- if (!sourceRepository) {
2474
- logger.error(
2475
- "No GitHub source found in lockfile. Cannot check for updates.\nRun 'agent-conf init --source <owner/repo>' to sync from a canonical repository first."
2476
- );
2477
- process.exit(1);
2478
- }
2479
- const spinner = logger.spinner("Checking for updates...");
2480
- spinner.start();
2481
- let latestRelease;
2482
- try {
2483
- latestRelease = await getLatestRelease(sourceRepository);
2484
- spinner.stop();
2485
- } catch (error) {
2486
- spinner.fail("Failed to check for updates");
2487
- logger.error(error instanceof Error ? error.message : String(error));
2488
- process.exit(1);
2489
- }
2490
- console.log();
2491
- console.log(`CLI version: ${pc10.cyan(currentCliVersion)}`);
2492
- console.log(`Canonical source: ${pc10.cyan(sourceRepository)}`);
2493
- console.log(`Latest release: ${pc10.cyan(latestRelease.tag)}`);
2494
- const currentRepoVersion = status.lockfile?.pinned_version;
2495
- const repoNeedsUpdate = currentRepoVersion ? compareVersions(currentRepoVersion, latestRelease.version) < 0 : false;
2496
- if (currentRepoVersion) {
2497
- console.log(`Pinned version: ${pc10.cyan(currentRepoVersion)}`);
2498
- if (repoNeedsUpdate) {
2499
- console.log(` ${pc10.yellow("\u2192")} Update available: ${latestRelease.version}`);
2500
- } else {
2501
- console.log(` ${pc10.green("\u2713")} Up to date`);
2502
- }
2503
- }
2504
- if (!repoNeedsUpdate) {
2505
- console.log();
2506
- prompts7.outro(pc10.green("Everything is up to date!"));
2507
- return;
2508
- }
2509
- console.log();
2510
- console.log(pc10.bold("Updates available:"));
2511
- console.log(` ${pc10.yellow("\u2192")} Canonical: ${currentRepoVersion} \u2192 ${latestRelease.version}`);
2512
- console.log();
2513
- if (!options.yes) {
2514
- const shouldUpdate = await prompts7.confirm({
2515
- message: "Proceed with update?",
2516
- initialValue: true
2517
- });
2518
- if (prompts7.isCancel(shouldUpdate) || !shouldUpdate) {
2519
- prompts7.cancel("Update cancelled");
2520
- process.exit(0);
2521
- }
2522
- }
2523
- console.log();
2524
- console.log(pc10.bold("Updating canonical content..."));
2525
- const targets = await parseAndValidateTargets(options.target);
2526
- const currentStatus = await getSyncStatus(gitRoot);
2527
- const resolvedVersion = {
2528
- ref: latestRelease.tag,
2529
- version: latestRelease.version,
2530
- isRelease: true,
2531
- releaseInfo: latestRelease
2532
- };
2533
- let tempDir = null;
2534
- try {
2535
- tempDir = await createTempDir();
2536
- const resolvedSource = await resolveGithubSource(
2537
- { repository: sourceRepository, ref: latestRelease.tag },
2538
- tempDir
2539
- );
2540
- await checkModifiedFilesBeforeSync(gitRoot, targets, options, tempDir);
2541
- const shouldOverride = await promptMergeOrOverride(
2542
- currentStatus,
2543
- { ...options, override: false },
2544
- tempDir
2545
- );
2546
- await performSync({
2547
- targetDir: gitRoot,
2548
- resolvedSource,
2549
- resolvedVersion,
2550
- shouldOverride,
2551
- targets,
2552
- context: {
2553
- commandName: "sync",
2554
- status: currentStatus
2555
- },
2556
- tempDir,
2557
- yes: options.yes,
2558
- sourceRepo: sourceRepository
2559
- });
2560
- } catch (error) {
2561
- if (tempDir) await removeTempDir(tempDir);
2562
- throw error;
2563
- }
2564
- prompts7.outro(pc10.green("Update complete!"));
2565
- }
2566
-
2567
2414
  // src/commands/upgrade-cli.ts
2568
2415
  import { execSync as execSync2 } from "child_process";
2569
- import * as path15 from "path";
2570
- import * as prompts8 from "@clack/prompts";
2571
- import pc11 from "picocolors";
2572
- function getPackageManager() {
2573
- try {
2574
- execSync2("pnpm --version", { stdio: "pipe" });
2575
- return "pnpm";
2576
- } catch {
2577
- return "npm";
2416
+ import * as prompts7 from "@clack/prompts";
2417
+ import pc10 from "picocolors";
2418
+ var NPM_PACKAGE_NAME = "agent-conf";
2419
+ async function getLatestNpmVersion() {
2420
+ const response = await fetch(`https://registry.npmjs.org/${NPM_PACKAGE_NAME}/latest`);
2421
+ if (!response.ok) {
2422
+ throw new Error(`Failed to fetch package info: ${response.statusText}`);
2578
2423
  }
2579
- }
2580
- function runCommand(command, cwd) {
2581
- execSync2(command, { cwd, stdio: "inherit" });
2424
+ const data = await response.json();
2425
+ return data.version;
2582
2426
  }
2583
2427
  async function upgradeCliCommand(options) {
2584
2428
  const logger = createLogger();
2585
2429
  const currentVersion = getCliVersion();
2586
2430
  console.log();
2587
- prompts8.intro(pc11.bold("agent-conf upgrade-cli"));
2588
- let cliRepo = options.repo;
2589
- if (!cliRepo) {
2590
- cliRepo = await getCliRepository();
2591
- }
2592
- if (!cliRepo) {
2593
- logger.error(
2594
- `No CLI repository configured.
2595
-
2596
- Specify the CLI repository using one of these methods:
2597
-
2598
- 1. Use the --repo flag:
2599
- agent-conf upgrade-cli --repo your-org/agent-conf
2600
-
2601
- 2. Set it in your global config (one-time setup):
2602
- agent-conf config set cli-repo your-org/agent-conf
2603
-
2604
- The CLI repository is where the agent-conf CLI tool is hosted,
2605
- NOT your canonical repository.`
2606
- );
2607
- process.exit(1);
2608
- }
2609
- if (options.repo) {
2610
- await setCliRepository(options.repo);
2611
- logger.info(`Saved CLI repository to config: ${options.repo}`);
2612
- }
2431
+ prompts7.intro(pc10.bold("agent-conf upgrade-cli"));
2613
2432
  const spinner = logger.spinner("Checking for CLI updates...");
2614
2433
  spinner.start();
2615
- let latestRelease;
2434
+ let latestVersion;
2616
2435
  try {
2617
- latestRelease = await getLatestRelease(cliRepo);
2436
+ latestVersion = await getLatestNpmVersion();
2618
2437
  spinner.stop();
2619
2438
  } catch (error) {
2620
2439
  spinner.fail("Failed to check for CLI updates");
@@ -2622,70 +2441,42 @@ NOT your canonical repository.`
2622
2441
  process.exit(1);
2623
2442
  }
2624
2443
  console.log();
2625
- console.log(`Current CLI version: ${pc11.cyan(currentVersion)}`);
2626
- console.log(`Latest CLI release: ${pc11.cyan(latestRelease.tag)}`);
2627
- console.log(`CLI repository: ${pc11.dim(cliRepo)}`);
2628
- const needsUpdate = compareVersions(currentVersion, latestRelease.version) < 0;
2444
+ console.log(`Current version: ${pc10.cyan(currentVersion)}`);
2445
+ console.log(`Latest version: ${pc10.cyan(latestVersion)}`);
2446
+ const needsUpdate = compareVersions(currentVersion, latestVersion) < 0;
2629
2447
  if (!needsUpdate) {
2630
2448
  console.log();
2631
- prompts8.outro(pc11.green("CLI is already up to date!"));
2449
+ prompts7.outro(pc10.green("CLI is already up to date!"));
2632
2450
  return;
2633
2451
  }
2634
2452
  console.log();
2635
- console.log(`${pc11.yellow("\u2192")} Update available: ${currentVersion} \u2192 ${latestRelease.version}`);
2453
+ console.log(`${pc10.yellow("\u2192")} Update available: ${currentVersion} \u2192 ${latestVersion}`);
2636
2454
  console.log();
2637
2455
  if (!options.yes) {
2638
- const shouldUpdate = await prompts8.confirm({
2456
+ const shouldUpdate = await prompts7.confirm({
2639
2457
  message: "Proceed with CLI upgrade?",
2640
2458
  initialValue: true
2641
2459
  });
2642
- if (prompts8.isCancel(shouldUpdate) || !shouldUpdate) {
2643
- prompts8.cancel("Upgrade cancelled");
2460
+ if (prompts7.isCancel(shouldUpdate) || !shouldUpdate) {
2461
+ prompts7.cancel("Upgrade cancelled");
2644
2462
  process.exit(0);
2645
2463
  }
2646
2464
  }
2647
- const pm = getPackageManager();
2648
- let tempDir = null;
2465
+ const installSpinner = logger.spinner("Upgrading CLI...");
2466
+ installSpinner.start();
2649
2467
  try {
2650
- const cloneSpinner = logger.spinner(`Cloning ${cliRepo}@${latestRelease.tag}...`);
2651
- cloneSpinner.start();
2652
- tempDir = await createTempDir("agent-conf-upgrade-");
2653
- const repoUrl = `https://github.com/${cliRepo}.git`;
2654
- runCommand(`git clone --depth 1 --branch ${latestRelease.tag} ${repoUrl} .`, tempDir);
2655
- cloneSpinner.succeed("Repository cloned");
2656
- const cliDir = path15.join(tempDir, "cli");
2657
- const installSpinner = logger.spinner("Installing dependencies...");
2658
- installSpinner.start();
2659
- if (pm === "pnpm") {
2660
- runCommand("pnpm install --frozen-lockfile", cliDir);
2661
- } else {
2662
- runCommand("npm ci", cliDir);
2663
- }
2664
- installSpinner.succeed("Dependencies installed");
2665
- const buildSpinner = logger.spinner("Building CLI...");
2666
- buildSpinner.start();
2667
- runCommand(`${pm} run build`, cliDir);
2668
- buildSpinner.succeed("Build complete");
2669
- const installGlobalSpinner = logger.spinner("Installing globally...");
2670
- installGlobalSpinner.start();
2671
- const packOutput = execSync2("npm pack --pack-destination /tmp", {
2672
- cwd: cliDir,
2673
- encoding: "utf-8"
2674
- }).trim();
2675
- const tarballPath = `/tmp/${packOutput}`;
2676
- runCommand(`npm install -g "${tarballPath}"`, cliDir);
2677
- execSync2(`rm -f "${tarballPath}"`, { stdio: "pipe" });
2678
- installGlobalSpinner.succeed("Installed globally");
2468
+ execSync2(`npm install -g ${NPM_PACKAGE_NAME}@latest`, {
2469
+ stdio: "pipe"
2470
+ });
2471
+ installSpinner.succeed("CLI upgraded");
2679
2472
  console.log();
2680
- prompts8.outro(pc11.green(`CLI upgraded to ${latestRelease.version}!`));
2473
+ prompts7.outro(pc10.green(`CLI upgraded to ${latestVersion}!`));
2681
2474
  } catch (error) {
2682
- logger.error("Upgrade failed");
2475
+ installSpinner.fail("Upgrade failed");
2683
2476
  logger.error(error instanceof Error ? error.message : String(error));
2477
+ logger.info(`
2478
+ You can try manually: npm install -g ${NPM_PACKAGE_NAME}@latest`);
2684
2479
  process.exit(1);
2685
- } finally {
2686
- if (tempDir) {
2687
- await removeTempDir(tempDir);
2688
- }
2689
2480
  }
2690
2481
  }
2691
2482
 
@@ -2702,12 +2493,12 @@ async function warnIfCliOutdated() {
2702
2493
  if (mismatch) {
2703
2494
  console.log();
2704
2495
  console.log(
2705
- pc12.yellow(
2496
+ pc11.yellow(
2706
2497
  `\u26A0 CLI is outdated: built from ${mismatch.cliCommit}, but repo was synced from ${mismatch.lockfileCommit}`
2707
2498
  )
2708
2499
  );
2709
2500
  console.log(
2710
- pc12.yellow(
2501
+ pc11.yellow(
2711
2502
  " Rebuild the CLI: cd <agent-conf-repo>/cli && pnpm build && pnpm link --global"
2712
2503
  )
2713
2504
  );
@@ -2729,10 +2520,10 @@ function createCli() {
2729
2520
  await initCommand(options);
2730
2521
  }
2731
2522
  );
2732
- program.command("sync").description("Sync agent-conf standards (skips initial setup prompts)").option(
2523
+ program.command("sync").description("Sync content from canonical repository (fetches latest by default)").option(
2733
2524
  "-s, --source <repo>",
2734
2525
  "Canonical repository in owner/repo format (e.g., acme/standards)"
2735
- ).option("--local [path]", "Use local canonical repository (auto-discover or specify path)").option("-y, --yes", "Non-interactive mode (merge by default)").option("--override", "Override existing AGENTS.md instead of merging").option("--ref <ref>", "GitHub ref/version to sync from (default: lockfile version)").option("-t, --target <targets...>", "Target platforms (claude, codex)", ["claude"]).action(
2526
+ ).option("--local [path]", "Use local canonical repository (auto-discover or specify path)").option("-y, --yes", "Non-interactive mode (merge by default)").option("--override", "Override existing AGENTS.md instead of merging").option("--ref <ref>", "GitHub ref/version to sync from").option("--pinned", "Use lockfile version without fetching latest").option("-t, --target <targets...>", "Target platforms (claude, codex)", ["claude"]).action(
2736
2527
  async (options) => {
2737
2528
  await syncCommand(options);
2738
2529
  }
@@ -2740,13 +2531,10 @@ function createCli() {
2740
2531
  program.command("status").description("Show current sync status").option("-c, --check", "Check for manually modified skill files").action(async (options) => {
2741
2532
  await statusCommand(options);
2742
2533
  });
2743
- program.command("update").description("Check for and apply updates from the canonical repository").option("-y, --yes", "Non-interactive mode").option("-t, --target <targets...>", "Target platforms (claude, codex)", ["claude"]).action(async (options) => {
2744
- await updateCommand(options);
2745
- });
2746
2534
  program.command("check").description("Check if managed files have been modified").option("-q, --quiet", "Minimal output, just exit code").action(async (options) => {
2747
2535
  await checkCommand(options);
2748
2536
  });
2749
- program.command("upgrade-cli").description("Upgrade the agent-conf CLI to the latest version").option("-r, --repo <repo>", "CLI repository in owner/repo format").option("-y, --yes", "Non-interactive mode").action(async (options) => {
2537
+ program.command("upgrade-cli").description("Upgrade the agent-conf CLI to the latest version").option("-y, --yes", "Non-interactive mode").action(async (options) => {
2750
2538
  await upgradeCliCommand(options);
2751
2539
  });
2752
2540
  const configCmd = program.command("config").description("Manage global CLI configuration");