agent-conf 1.0.0 → 1.0.2
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/README.md +6 -0
- package/dist/index.js +171 -303
- package/dist/index.js.map +1 -1
- package/package.json +9 -3
package/dist/index.js
CHANGED
|
@@ -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 ? "
|
|
69
|
+
return true ? "c08e69369bbaf54887a5b0f93bcfca7c6b0d10e9" : "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: ["-
|
|
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
|
-
|
|
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
|
-
|
|
554
|
-
|
|
555
|
-
|
|
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,
|
|
519
|
+
async function configSetCommand(key, _value) {
|
|
571
520
|
const logger = createLogger();
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
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
|
|
590
|
-
import * as
|
|
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
|
|
595
|
-
import * as
|
|
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
|
|
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 =
|
|
608
|
-
const rootClaudeMdPath =
|
|
609
|
-
const dotClaudeClaudeMdPath =
|
|
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 =
|
|
663
|
-
await
|
|
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 =
|
|
667
|
-
const dotClaudePath =
|
|
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
|
|
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
|
|
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
|
|
693
|
-
await
|
|
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
|
|
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 =
|
|
692
|
+
const skillMdPath = path5.join(resolvedSource.skillsPath, skillName, "SKILL.md");
|
|
751
693
|
try {
|
|
752
|
-
const content = await
|
|
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 =
|
|
759
|
+
const targetSkillsPath = path5.join(targetDir, config.dir, "skills");
|
|
818
760
|
let copied = 0;
|
|
819
761
|
for (const skillName of skillNames) {
|
|
820
|
-
const sourceDir =
|
|
821
|
-
const targetSkillDir =
|
|
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
|
|
829
|
-
const entries = await
|
|
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 =
|
|
833
|
-
const targetPath =
|
|
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
|
|
779
|
+
const content = await fs5.readFile(sourcePath, "utf-8");
|
|
838
780
|
const contentWithMetadata = addManagedMetadata(content);
|
|
839
|
-
await
|
|
781
|
+
await fs5.writeFile(targetPath, contentWithMetadata, "utf-8");
|
|
840
782
|
copied++;
|
|
841
783
|
} else {
|
|
842
|
-
await
|
|
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 =
|
|
863
|
-
const skillsPath =
|
|
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
|
-
|
|
866
|
-
|
|
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 =
|
|
826
|
+
const skillDir = path5.join(targetDir, `.${target}`, "skills", skillName);
|
|
885
827
|
try {
|
|
886
|
-
await
|
|
828
|
+
await fs5.access(skillDir);
|
|
887
829
|
} catch {
|
|
888
830
|
continue;
|
|
889
831
|
}
|
|
890
|
-
const skillMdPath =
|
|
832
|
+
const skillMdPath = path5.join(skillDir, "SKILL.md");
|
|
891
833
|
try {
|
|
892
|
-
const content = await
|
|
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
|
|
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
|
|
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
|
|
931
|
-
import * as
|
|
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 =
|
|
998
|
-
const hookPath =
|
|
939
|
+
const hooksDir = path6.join(targetDir, ".git", "hooks");
|
|
940
|
+
const hookPath = path6.join(hooksDir, "pre-commit");
|
|
999
941
|
const hookContent = generatePreCommitHook(hookConfig);
|
|
1000
|
-
await
|
|
942
|
+
await fs6.mkdir(hooksDir, { recursive: true });
|
|
1001
943
|
let existingContent = null;
|
|
1002
944
|
try {
|
|
1003
|
-
existingContent = await
|
|
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
|
|
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
|
|
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
|
|
1043
|
-
import * as
|
|
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 =
|
|
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:
|
|
1070
|
-
skillsPath:
|
|
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:
|
|
1091
|
-
skillsPath:
|
|
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 =
|
|
1096
|
-
const 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 =
|
|
1044
|
+
checkDir = path7.dirname(checkDir);
|
|
1103
1045
|
}
|
|
1104
|
-
currentDir =
|
|
1046
|
+
currentDir = path7.resolve(startDir);
|
|
1105
1047
|
while (currentDir !== root) {
|
|
1106
|
-
const parentDir =
|
|
1107
|
-
const siblingCanonicalRepo =
|
|
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
|
|
1061
|
+
const stat4 = await fs7.stat(dir).catch(() => null);
|
|
1120
1062
|
if (!stat4?.isDirectory()) {
|
|
1121
1063
|
return false;
|
|
1122
1064
|
}
|
|
1123
|
-
const instructionsPath =
|
|
1124
|
-
const skillsPath =
|
|
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
|
-
|
|
1127
|
-
|
|
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 =
|
|
1150
|
-
const skillsPath =
|
|
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
|
-
|
|
1153
|
-
|
|
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
|
|
1273
|
-
import * as
|
|
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
|
|
1244
|
+
return path8.join(repoRoot, WORKFLOWS_DIR);
|
|
1303
1245
|
}
|
|
1304
1246
|
function getWorkflowPath(repoRoot, filename) {
|
|
1305
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1434
|
-
import * as
|
|
1435
|
-
import * as
|
|
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
|
|
1379
|
+
await fs9.mkdir(dirPath, { recursive: true });
|
|
1438
1380
|
}
|
|
1439
1381
|
async function fileExists(filePath) {
|
|
1440
1382
|
try {
|
|
1441
|
-
await
|
|
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
|
|
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 =
|
|
1457
|
-
return
|
|
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
|
|
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
|
|
1409
|
+
return path9.join(os2.homedir(), inputPath.slice(1));
|
|
1468
1410
|
}
|
|
1469
|
-
return
|
|
1411
|
+
return path9.resolve(inputPath);
|
|
1470
1412
|
}
|
|
1471
1413
|
|
|
1472
1414
|
// src/utils/git.ts
|
|
1473
|
-
import * as
|
|
1474
|
-
import * as
|
|
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
|
|
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
|
|
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
|
|
1517
|
-
const realGitRoot = await
|
|
1458
|
+
const realDir = await fs10.realpath(dir);
|
|
1459
|
+
const realGitRoot = await fs10.realpath(gitRoot);
|
|
1518
1460
|
return realDir === realGitRoot;
|
|
1519
1461
|
} catch {
|
|
1520
|
-
return
|
|
1462
|
+
return path10.resolve(dir) === path10.resolve(gitRoot);
|
|
1521
1463
|
}
|
|
1522
1464
|
}
|
|
1523
1465
|
async function getGitOrganization(dir) {
|
|
@@ -1822,7 +1764,7 @@ async function performSync(options) {
|
|
|
1822
1764
|
console.log();
|
|
1823
1765
|
console.log(pc5.bold("Sync complete:"));
|
|
1824
1766
|
console.log();
|
|
1825
|
-
const agentsMdPath = formatPath(
|
|
1767
|
+
const agentsMdPath = formatPath(path11.join(targetDir, "AGENTS.md"));
|
|
1826
1768
|
if (result.agentsMd.merged) {
|
|
1827
1769
|
const label = context.commandName === "sync" ? "(updated)" : "(merged)";
|
|
1828
1770
|
console.log(` ${pc5.green("+")} ${agentsMdPath} ${pc5.dim(label)}`);
|
|
@@ -1832,7 +1774,7 @@ async function performSync(options) {
|
|
|
1832
1774
|
for (const targetResult of result.targets) {
|
|
1833
1775
|
const config = getTargetConfig(targetResult.target);
|
|
1834
1776
|
if (config.instructionsFile) {
|
|
1835
|
-
const instructionsPath = targetResult.instructionsMd.location === "root" ? formatPath(
|
|
1777
|
+
const instructionsPath = targetResult.instructionsMd.location === "root" ? formatPath(path11.join(targetDir, config.instructionsFile)) : formatPath(path11.join(targetDir, config.dir, config.instructionsFile));
|
|
1836
1778
|
if (targetResult.instructionsMd.created) {
|
|
1837
1779
|
console.log(` ${pc5.green("+")} ${instructionsPath} ${pc5.dim("(created)")}`);
|
|
1838
1780
|
} else if (targetResult.instructionsMd.updated) {
|
|
@@ -1842,13 +1784,13 @@ async function performSync(options) {
|
|
|
1842
1784
|
console.log(` ${pc5.dim("-")} ${instructionsPath} ${pc5.dim("(unchanged)")}`);
|
|
1843
1785
|
}
|
|
1844
1786
|
}
|
|
1845
|
-
const skillsPath = formatPath(
|
|
1787
|
+
const skillsPath = formatPath(path11.join(targetDir, config.dir, "skills"));
|
|
1846
1788
|
console.log(
|
|
1847
1789
|
` ${pc5.green("+")} ${skillsPath}/ ${pc5.dim(`(${result.skills.synced.length} skills, ${targetResult.skills.copied} files)`)}`
|
|
1848
1790
|
);
|
|
1849
1791
|
if (orphanResult.deleted.length > 0) {
|
|
1850
1792
|
for (const skill of orphanResult.deleted) {
|
|
1851
|
-
const orphanPath = formatPath(
|
|
1793
|
+
const orphanPath = formatPath(path11.join(targetDir, config.dir, "skills", skill));
|
|
1852
1794
|
console.log(
|
|
1853
1795
|
` ${pc5.red("-")} ${orphanPath}/ ${pc5.dim("(removed - no longer in source)")}`
|
|
1854
1796
|
);
|
|
@@ -1856,28 +1798,28 @@ async function performSync(options) {
|
|
|
1856
1798
|
}
|
|
1857
1799
|
if (orphanResult.skipped.length > 0) {
|
|
1858
1800
|
for (const skill of orphanResult.skipped) {
|
|
1859
|
-
const orphanPath = formatPath(
|
|
1801
|
+
const orphanPath = formatPath(path11.join(targetDir, config.dir, "skills", skill));
|
|
1860
1802
|
console.log(` ${pc5.yellow("!")} ${orphanPath}/ ${pc5.dim("(orphaned but skipped)")}`);
|
|
1861
1803
|
}
|
|
1862
1804
|
}
|
|
1863
1805
|
}
|
|
1864
1806
|
if (workflowResult) {
|
|
1865
1807
|
for (const filename of workflowResult.created) {
|
|
1866
|
-
const workflowPath = formatPath(
|
|
1808
|
+
const workflowPath = formatPath(path11.join(targetDir, ".github/workflows", filename));
|
|
1867
1809
|
console.log(` ${pc5.green("+")} ${workflowPath} ${pc5.dim("(created)")}`);
|
|
1868
1810
|
}
|
|
1869
1811
|
for (const filename of workflowResult.updated) {
|
|
1870
|
-
const workflowPath = formatPath(
|
|
1812
|
+
const workflowPath = formatPath(path11.join(targetDir, ".github/workflows", filename));
|
|
1871
1813
|
console.log(` ${pc5.yellow("~")} ${workflowPath} ${pc5.dim("(updated)")}`);
|
|
1872
1814
|
}
|
|
1873
1815
|
for (const filename of workflowResult.unchanged) {
|
|
1874
|
-
const workflowPath = formatPath(
|
|
1816
|
+
const workflowPath = formatPath(path11.join(targetDir, ".github/workflows", filename));
|
|
1875
1817
|
console.log(` ${pc5.dim("-")} ${workflowPath} ${pc5.dim("(unchanged)")}`);
|
|
1876
1818
|
}
|
|
1877
1819
|
}
|
|
1878
|
-
const lockfilePath = formatPath(
|
|
1820
|
+
const lockfilePath = formatPath(path11.join(targetDir, ".agent-conf", "agent-conf.lock"));
|
|
1879
1821
|
console.log(` ${pc5.green("+")} ${lockfilePath}`);
|
|
1880
|
-
const hookPath = formatPath(
|
|
1822
|
+
const hookPath = formatPath(path11.join(targetDir, ".git/hooks/pre-commit"));
|
|
1881
1823
|
if (hookResult.installed) {
|
|
1882
1824
|
if (hookResult.alreadyExisted && !hookResult.wasUpdated) {
|
|
1883
1825
|
console.log(` ${pc5.dim("-")} ${hookPath} ${pc5.dim("(unchanged)")}`);
|
|
@@ -1947,8 +1889,8 @@ async function initCommand(options) {
|
|
|
1947
1889
|
}
|
|
1948
1890
|
|
|
1949
1891
|
// src/commands/init-canonical-repo.ts
|
|
1950
|
-
import * as
|
|
1951
|
-
import * as
|
|
1892
|
+
import * as fs11 from "fs/promises";
|
|
1893
|
+
import * as path12 from "path";
|
|
1952
1894
|
import * as prompts5 from "@clack/prompts";
|
|
1953
1895
|
import pc7 from "picocolors";
|
|
1954
1896
|
import { stringify as stringifyYaml } from "yaml";
|
|
@@ -2052,9 +1994,6 @@ function generateSyncWorkflow2(repoFullName, prefix) {
|
|
|
2052
1994
|
#
|
|
2053
1995
|
# Downstream repos will reference this workflow like:
|
|
2054
1996
|
# 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 docs/CANONICAL_REPOSITORY_SETUP.md for detailed instructions.
|
|
2058
1997
|
|
|
2059
1998
|
name: Sync Reusable
|
|
2060
1999
|
|
|
@@ -2090,13 +2029,7 @@ jobs:
|
|
|
2090
2029
|
node-version: '20'
|
|
2091
2030
|
|
|
2092
2031
|
- 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 docs/CANONICAL_REPOSITORY_SETUP.md"
|
|
2099
|
-
exit 1
|
|
2032
|
+
run: npm install -g agent-conf
|
|
2100
2033
|
|
|
2101
2034
|
- name: Run sync
|
|
2102
2035
|
run: |
|
|
@@ -2111,9 +2044,6 @@ function generateCheckWorkflow2(repoFullName, prefix) {
|
|
|
2111
2044
|
#
|
|
2112
2045
|
# Downstream repos will reference this workflow like:
|
|
2113
2046
|
# 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 docs/CANONICAL_REPOSITORY_SETUP.md for detailed instructions.
|
|
2117
2047
|
|
|
2118
2048
|
name: Check Reusable
|
|
2119
2049
|
|
|
@@ -2139,13 +2069,7 @@ jobs:
|
|
|
2139
2069
|
node-version: '20'
|
|
2140
2070
|
|
|
2141
2071
|
- 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 docs/CANONICAL_REPOSITORY_SETUP.md"
|
|
2148
|
-
exit 1
|
|
2072
|
+
run: npm install -g agent-conf
|
|
2149
2073
|
|
|
2150
2074
|
- name: Check file integrity
|
|
2151
2075
|
run: |
|
|
@@ -2156,8 +2080,8 @@ async function initCanonicalRepoCommand(options) {
|
|
|
2156
2080
|
const logger = createLogger();
|
|
2157
2081
|
console.log();
|
|
2158
2082
|
prompts5.intro(pc7.bold("agent-conf init-canonical-repo"));
|
|
2159
|
-
const targetDir = options.dir ?
|
|
2160
|
-
const dirName =
|
|
2083
|
+
const targetDir = options.dir ? path12.resolve(options.dir) : process.cwd();
|
|
2084
|
+
const dirName = path12.basename(targetDir);
|
|
2161
2085
|
const cwd = process.cwd();
|
|
2162
2086
|
let isAtGitRoot = await isGitRoot(targetDir);
|
|
2163
2087
|
let gitProjectName = await getGitProjectName(targetDir);
|
|
@@ -2166,7 +2090,7 @@ async function initCanonicalRepoCommand(options) {
|
|
|
2166
2090
|
const cwdIsGitRoot = await isGitRoot(cwd);
|
|
2167
2091
|
const cwdGitProjectName = await getGitProjectName(cwd);
|
|
2168
2092
|
const cwdGitOrganization = await getGitOrganization(cwd);
|
|
2169
|
-
if (cwdIsGitRoot &&
|
|
2093
|
+
if (cwdIsGitRoot && path12.resolve(targetDir) === path12.resolve(cwd)) {
|
|
2170
2094
|
isAtGitRoot = true;
|
|
2171
2095
|
gitProjectName = cwdGitProjectName;
|
|
2172
2096
|
gitOrganization = cwdGitOrganization;
|
|
@@ -2185,7 +2109,7 @@ async function initCanonicalRepoCommand(options) {
|
|
|
2185
2109
|
}
|
|
2186
2110
|
const dirExists = await directoryExists(targetDir);
|
|
2187
2111
|
if (dirExists) {
|
|
2188
|
-
const configExists = await fileExists(
|
|
2112
|
+
const configExists = await fileExists(path12.join(targetDir, "agent-conf.yaml"));
|
|
2189
2113
|
if (configExists && !options.yes) {
|
|
2190
2114
|
const shouldContinue = await prompts5.confirm({
|
|
2191
2115
|
message: "This directory already has an agent-conf.yaml. Overwrite?",
|
|
@@ -2267,34 +2191,34 @@ async function initCanonicalRepoCommand(options) {
|
|
|
2267
2191
|
spinner.start();
|
|
2268
2192
|
try {
|
|
2269
2193
|
await ensureDir(resolvedOptions.targetDir);
|
|
2270
|
-
const instructionsDir =
|
|
2271
|
-
const skillsDir =
|
|
2272
|
-
const workflowsDir =
|
|
2194
|
+
const instructionsDir = path12.join(resolvedOptions.targetDir, "instructions");
|
|
2195
|
+
const skillsDir = path12.join(resolvedOptions.targetDir, "skills");
|
|
2196
|
+
const workflowsDir = path12.join(resolvedOptions.targetDir, ".github", "workflows");
|
|
2273
2197
|
await ensureDir(instructionsDir);
|
|
2274
2198
|
await ensureDir(skillsDir);
|
|
2275
2199
|
await ensureDir(workflowsDir);
|
|
2276
|
-
const configPath =
|
|
2277
|
-
await
|
|
2278
|
-
const agentsMdPath =
|
|
2279
|
-
await
|
|
2200
|
+
const configPath = path12.join(resolvedOptions.targetDir, "agent-conf.yaml");
|
|
2201
|
+
await fs11.writeFile(configPath, generateConfigYaml(resolvedOptions), "utf-8");
|
|
2202
|
+
const agentsMdPath = path12.join(instructionsDir, "AGENTS.md");
|
|
2203
|
+
await fs11.writeFile(agentsMdPath, generateAgentsMd(resolvedOptions), "utf-8");
|
|
2280
2204
|
if (resolvedOptions.includeExamples) {
|
|
2281
|
-
const exampleSkillDir =
|
|
2282
|
-
const referencesDir =
|
|
2205
|
+
const exampleSkillDir = path12.join(skillsDir, "example-skill");
|
|
2206
|
+
const referencesDir = path12.join(exampleSkillDir, "references");
|
|
2283
2207
|
await ensureDir(referencesDir);
|
|
2284
|
-
const skillMdPath =
|
|
2285
|
-
await
|
|
2286
|
-
const gitkeepPath =
|
|
2287
|
-
await
|
|
2208
|
+
const skillMdPath = path12.join(exampleSkillDir, "SKILL.md");
|
|
2209
|
+
await fs11.writeFile(skillMdPath, generateExampleSkillMd(), "utf-8");
|
|
2210
|
+
const gitkeepPath = path12.join(referencesDir, ".gitkeep");
|
|
2211
|
+
await fs11.writeFile(gitkeepPath, "", "utf-8");
|
|
2288
2212
|
}
|
|
2289
|
-
const syncWorkflowPath =
|
|
2290
|
-
const checkWorkflowPath =
|
|
2213
|
+
const syncWorkflowPath = path12.join(workflowsDir, "sync-reusable.yml");
|
|
2214
|
+
const checkWorkflowPath = path12.join(workflowsDir, "check-reusable.yml");
|
|
2291
2215
|
const repoFullName = resolvedOptions.organization ? `${resolvedOptions.organization}/${resolvedOptions.name}` : resolvedOptions.name;
|
|
2292
|
-
await
|
|
2216
|
+
await fs11.writeFile(
|
|
2293
2217
|
syncWorkflowPath,
|
|
2294
2218
|
generateSyncWorkflow2(repoFullName, resolvedOptions.markerPrefix),
|
|
2295
2219
|
"utf-8"
|
|
2296
2220
|
);
|
|
2297
|
-
await
|
|
2221
|
+
await fs11.writeFile(
|
|
2298
2222
|
checkWorkflowPath,
|
|
2299
2223
|
generateCheckWorkflow2(repoFullName, resolvedOptions.markerPrefix),
|
|
2300
2224
|
"utf-8"
|
|
@@ -2306,7 +2230,7 @@ async function initCanonicalRepoCommand(options) {
|
|
|
2306
2230
|
console.log(` ${pc7.green("+")} ${formatPath(agentsMdPath)}`);
|
|
2307
2231
|
if (resolvedOptions.includeExamples) {
|
|
2308
2232
|
console.log(
|
|
2309
|
-
` ${pc7.green("+")} ${formatPath(
|
|
2233
|
+
` ${pc7.green("+")} ${formatPath(path12.join(skillsDir, "example-skill/SKILL.md"))}`
|
|
2310
2234
|
);
|
|
2311
2235
|
}
|
|
2312
2236
|
console.log(` ${pc7.green("+")} ${formatPath(syncWorkflowPath)}`);
|
|
@@ -2321,13 +2245,13 @@ async function initCanonicalRepoCommand(options) {
|
|
|
2321
2245
|
console.log(pc7.bold("Next steps:"));
|
|
2322
2246
|
console.log(` 1. Edit ${pc7.cyan("instructions/AGENTS.md")} with your engineering standards`);
|
|
2323
2247
|
console.log(` 2. Add skills to ${pc7.cyan("skills/")} directory`);
|
|
2248
|
+
console.log(` 3. Commit and push to create your canonical repository`);
|
|
2249
|
+
console.log();
|
|
2324
2250
|
console.log(
|
|
2325
|
-
|
|
2251
|
+
pc7.dim(
|
|
2252
|
+
`See https://github.com/julian-pani/agent-conf/blob/master/cli/docs/CANONICAL_REPOSITORY_SETUP.md for detailed setup instructions.`
|
|
2253
|
+
)
|
|
2326
2254
|
);
|
|
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 docs/CANONICAL_REPOSITORY_SETUP.md for detailed setup instructions.`));
|
|
2331
2255
|
prompts5.outro(pc7.green("Done!"));
|
|
2332
2256
|
} catch (error) {
|
|
2333
2257
|
spinner.fail("Failed to create canonical repository");
|
|
@@ -2337,7 +2261,7 @@ async function initCanonicalRepoCommand(options) {
|
|
|
2337
2261
|
}
|
|
2338
2262
|
|
|
2339
2263
|
// src/commands/status.ts
|
|
2340
|
-
import * as
|
|
2264
|
+
import * as path13 from "path";
|
|
2341
2265
|
import pc8 from "picocolors";
|
|
2342
2266
|
async function statusCommand(options = {}) {
|
|
2343
2267
|
const targetDir = process.cwd();
|
|
@@ -2390,7 +2314,7 @@ async function statusCommand(options = {}) {
|
|
|
2390
2314
|
}
|
|
2391
2315
|
console.log();
|
|
2392
2316
|
}
|
|
2393
|
-
const lockfilePath = formatPath(
|
|
2317
|
+
const lockfilePath = formatPath(path13.join(targetDir, ".agent-conf", "agent-conf.lock"));
|
|
2394
2318
|
console.log(pc8.dim(`Lock file: ${lockfilePath}`));
|
|
2395
2319
|
console.log(pc8.dim(`CLI version: ${lockfile.cli_version}`));
|
|
2396
2320
|
console.log();
|
|
@@ -2566,55 +2490,27 @@ async function updateCommand(options) {
|
|
|
2566
2490
|
|
|
2567
2491
|
// src/commands/upgrade-cli.ts
|
|
2568
2492
|
import { execSync as execSync2 } from "child_process";
|
|
2569
|
-
import * as path15 from "path";
|
|
2570
2493
|
import * as prompts8 from "@clack/prompts";
|
|
2571
2494
|
import pc11 from "picocolors";
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
return "npm";
|
|
2495
|
+
var NPM_PACKAGE_NAME = "agent-conf";
|
|
2496
|
+
async function getLatestNpmVersion() {
|
|
2497
|
+
const response = await fetch(`https://registry.npmjs.org/${NPM_PACKAGE_NAME}/latest`);
|
|
2498
|
+
if (!response.ok) {
|
|
2499
|
+
throw new Error(`Failed to fetch package info: ${response.statusText}`);
|
|
2578
2500
|
}
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
execSync2(command, { cwd, stdio: "inherit" });
|
|
2501
|
+
const data = await response.json();
|
|
2502
|
+
return data.version;
|
|
2582
2503
|
}
|
|
2583
2504
|
async function upgradeCliCommand(options) {
|
|
2584
2505
|
const logger = createLogger();
|
|
2585
2506
|
const currentVersion = getCliVersion();
|
|
2586
2507
|
console.log();
|
|
2587
2508
|
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
|
-
}
|
|
2613
2509
|
const spinner = logger.spinner("Checking for CLI updates...");
|
|
2614
2510
|
spinner.start();
|
|
2615
|
-
let
|
|
2511
|
+
let latestVersion;
|
|
2616
2512
|
try {
|
|
2617
|
-
|
|
2513
|
+
latestVersion = await getLatestNpmVersion();
|
|
2618
2514
|
spinner.stop();
|
|
2619
2515
|
} catch (error) {
|
|
2620
2516
|
spinner.fail("Failed to check for CLI updates");
|
|
@@ -2622,17 +2518,16 @@ NOT your canonical repository.`
|
|
|
2622
2518
|
process.exit(1);
|
|
2623
2519
|
}
|
|
2624
2520
|
console.log();
|
|
2625
|
-
console.log(`Current
|
|
2626
|
-
console.log(`Latest
|
|
2627
|
-
|
|
2628
|
-
const needsUpdate = compareVersions(currentVersion, latestRelease.version) < 0;
|
|
2521
|
+
console.log(`Current version: ${pc11.cyan(currentVersion)}`);
|
|
2522
|
+
console.log(`Latest version: ${pc11.cyan(latestVersion)}`);
|
|
2523
|
+
const needsUpdate = compareVersions(currentVersion, latestVersion) < 0;
|
|
2629
2524
|
if (!needsUpdate) {
|
|
2630
2525
|
console.log();
|
|
2631
2526
|
prompts8.outro(pc11.green("CLI is already up to date!"));
|
|
2632
2527
|
return;
|
|
2633
2528
|
}
|
|
2634
2529
|
console.log();
|
|
2635
|
-
console.log(`${pc11.yellow("\u2192")} Update available: ${currentVersion} \u2192 ${
|
|
2530
|
+
console.log(`${pc11.yellow("\u2192")} Update available: ${currentVersion} \u2192 ${latestVersion}`);
|
|
2636
2531
|
console.log();
|
|
2637
2532
|
if (!options.yes) {
|
|
2638
2533
|
const shouldUpdate = await prompts8.confirm({
|
|
@@ -2644,48 +2539,21 @@ NOT your canonical repository.`
|
|
|
2644
2539
|
process.exit(0);
|
|
2645
2540
|
}
|
|
2646
2541
|
}
|
|
2647
|
-
const
|
|
2648
|
-
|
|
2542
|
+
const installSpinner = logger.spinner("Upgrading CLI...");
|
|
2543
|
+
installSpinner.start();
|
|
2649
2544
|
try {
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
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");
|
|
2545
|
+
execSync2(`npm install -g ${NPM_PACKAGE_NAME}@latest`, {
|
|
2546
|
+
stdio: "pipe"
|
|
2547
|
+
});
|
|
2548
|
+
installSpinner.succeed("CLI upgraded");
|
|
2679
2549
|
console.log();
|
|
2680
|
-
prompts8.outro(pc11.green(`CLI upgraded to ${
|
|
2550
|
+
prompts8.outro(pc11.green(`CLI upgraded to ${latestVersion}!`));
|
|
2681
2551
|
} catch (error) {
|
|
2682
|
-
|
|
2552
|
+
installSpinner.fail("Upgrade failed");
|
|
2683
2553
|
logger.error(error instanceof Error ? error.message : String(error));
|
|
2554
|
+
logger.info(`
|
|
2555
|
+
You can try manually: npm install -g ${NPM_PACKAGE_NAME}@latest`);
|
|
2684
2556
|
process.exit(1);
|
|
2685
|
-
} finally {
|
|
2686
|
-
if (tempDir) {
|
|
2687
|
-
await removeTempDir(tempDir);
|
|
2688
|
-
}
|
|
2689
2557
|
}
|
|
2690
2558
|
}
|
|
2691
2559
|
|
|
@@ -2746,7 +2614,7 @@ function createCli() {
|
|
|
2746
2614
|
program.command("check").description("Check if managed files have been modified").option("-q, --quiet", "Minimal output, just exit code").action(async (options) => {
|
|
2747
2615
|
await checkCommand(options);
|
|
2748
2616
|
});
|
|
2749
|
-
program.command("upgrade-cli").description("Upgrade the agent-conf CLI to the latest version").option("-
|
|
2617
|
+
program.command("upgrade-cli").description("Upgrade the agent-conf CLI to the latest version").option("-y, --yes", "Non-interactive mode").action(async (options) => {
|
|
2750
2618
|
await upgradeCliCommand(options);
|
|
2751
2619
|
});
|
|
2752
2620
|
const configCmd = program.command("config").description("Manage global CLI configuration");
|