agent-conf 2.0.4 → 2.1.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/{chunk-EN5LTDER.js → chunk-MZ2GBXCB.js} +20 -17
- package/dist/chunk-MZ2GBXCB.js.map +1 -0
- package/dist/index.js +167 -104
- package/dist/index.js.map +1 -1
- package/dist/{skill-metadata-XANK6RZP.js → skill-metadata-DK2WBJJ3.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-EN5LTDER.js.map +0 -1
- /package/dist/{skill-metadata-XANK6RZP.js.map → skill-metadata-DK2WBJJ3.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
CanonicalRepoConfigSchema,
|
|
3
4
|
addManagedMetadata,
|
|
4
5
|
buildAgentsMd,
|
|
5
6
|
checkAllManagedFiles,
|
|
@@ -12,7 +13,7 @@ import {
|
|
|
12
13
|
parseGlobalBlockMetadata,
|
|
13
14
|
stripMetadataComments,
|
|
14
15
|
validateSkillFrontmatter
|
|
15
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-MZ2GBXCB.js";
|
|
16
17
|
|
|
17
18
|
// src/cli.ts
|
|
18
19
|
import { Command } from "commander";
|
|
@@ -49,7 +50,9 @@ var ContentSchema = z.object({
|
|
|
49
50
|
merged: z.boolean()
|
|
50
51
|
}),
|
|
51
52
|
skills: z.array(z.string()),
|
|
52
|
-
targets: z.array(z.string()).optional()
|
|
53
|
+
targets: z.array(z.string()).optional(),
|
|
54
|
+
/** Marker prefix used for managed content (default: "agent-conf") */
|
|
55
|
+
marker_prefix: z.string().optional()
|
|
53
56
|
});
|
|
54
57
|
var LockfileSchema = z.object({
|
|
55
58
|
version: z.literal("1"),
|
|
@@ -66,7 +69,7 @@ var CONFIG_DIR = ".agent-conf";
|
|
|
66
69
|
var LOCKFILE_NAME = "lockfile.json";
|
|
67
70
|
var CLI_VERSION = "0.1.0";
|
|
68
71
|
function getBuildCommit() {
|
|
69
|
-
return true ? "
|
|
72
|
+
return true ? "495cb19c3410dc3d585d83d93279944ff665eb9e" : "unknown";
|
|
70
73
|
}
|
|
71
74
|
function getLockfilePath(targetDir) {
|
|
72
75
|
return path.join(targetDir, CONFIG_DIR, LOCKFILE_NAME);
|
|
@@ -97,7 +100,8 @@ async function writeLockfile(targetDir, options) {
|
|
|
97
100
|
merged: true
|
|
98
101
|
},
|
|
99
102
|
skills: options.skills,
|
|
100
|
-
targets: options.targets ?? ["claude"]
|
|
103
|
+
targets: options.targets ?? ["claude"],
|
|
104
|
+
marker_prefix: options.markerPrefix
|
|
101
105
|
},
|
|
102
106
|
cli_version: CLI_VERSION
|
|
103
107
|
};
|
|
@@ -153,14 +157,17 @@ async function checkCommand(options = {}) {
|
|
|
153
157
|
return;
|
|
154
158
|
}
|
|
155
159
|
const targets = lockfile.content.targets ?? ["claude"];
|
|
160
|
+
const markerPrefix = lockfile.content.marker_prefix;
|
|
156
161
|
const modifiedFiles = [];
|
|
157
|
-
const
|
|
162
|
+
const checkOptions = markerPrefix ? { markerPrefix, metadataPrefix: markerPrefix } : {};
|
|
163
|
+
const allFiles = await checkAllManagedFiles(targetDir, targets, checkOptions);
|
|
164
|
+
const keyPrefix = markerPrefix ? `${markerPrefix.replace(/-/g, "_")}_` : "agent_conf_";
|
|
158
165
|
for (const file of allFiles) {
|
|
159
166
|
if (!file.hasChanges) continue;
|
|
160
167
|
if (file.type === "agents") {
|
|
161
168
|
const agentsMdPath = path2.join(targetDir, "AGENTS.md");
|
|
162
169
|
const content = await fs2.readFile(agentsMdPath, "utf-8");
|
|
163
|
-
const parsed = parseAgentsMd(content);
|
|
170
|
+
const parsed = parseAgentsMd(content, markerPrefix ? { prefix: markerPrefix } : void 0);
|
|
164
171
|
if (parsed.globalBlock) {
|
|
165
172
|
const metadata = parseGlobalBlockMetadata(parsed.globalBlock);
|
|
166
173
|
const contentWithoutMeta = stripMetadataComments(parsed.globalBlock);
|
|
@@ -177,8 +184,11 @@ async function checkCommand(options = {}) {
|
|
|
177
184
|
const content = await fs2.readFile(skillPath, "utf-8");
|
|
178
185
|
const { frontmatter } = parseFrontmatter(content);
|
|
179
186
|
const metadata = frontmatter.metadata;
|
|
180
|
-
const storedHash = metadata?.
|
|
181
|
-
const currentHash = computeContentHash(
|
|
187
|
+
const storedHash = metadata?.[`${keyPrefix}content_hash`] ?? "unknown";
|
|
188
|
+
const currentHash = computeContentHash(
|
|
189
|
+
content,
|
|
190
|
+
markerPrefix ? { metadataPrefix: markerPrefix } : void 0
|
|
191
|
+
);
|
|
182
192
|
modifiedFiles.push({
|
|
183
193
|
path: file.path,
|
|
184
194
|
type: "skill",
|
|
@@ -187,6 +197,23 @@ async function checkCommand(options = {}) {
|
|
|
187
197
|
});
|
|
188
198
|
}
|
|
189
199
|
}
|
|
200
|
+
if (allFiles.length === 0) {
|
|
201
|
+
if (options.quiet) {
|
|
202
|
+
process.exit(1);
|
|
203
|
+
}
|
|
204
|
+
console.log();
|
|
205
|
+
console.log(pc.bold("agent-conf check"));
|
|
206
|
+
console.log();
|
|
207
|
+
console.log(`${pc.red("\u2717")} No managed files found`);
|
|
208
|
+
console.log();
|
|
209
|
+
console.log(pc.dim("This repository appears to be synced but no managed files were detected."));
|
|
210
|
+
if (markerPrefix) {
|
|
211
|
+
console.log(pc.dim(`Expected marker prefix: ${markerPrefix}`));
|
|
212
|
+
}
|
|
213
|
+
console.log(pc.dim("Run 'agent-conf sync' to restore the managed files."));
|
|
214
|
+
console.log();
|
|
215
|
+
process.exit(1);
|
|
216
|
+
}
|
|
190
217
|
if (options.quiet) {
|
|
191
218
|
if (modifiedFiles.length > 0) {
|
|
192
219
|
process.exit(1);
|
|
@@ -568,9 +595,10 @@ function stripAgentsReference(content) {
|
|
|
568
595
|
}
|
|
569
596
|
async function mergeAgentsMd(targetDir, globalContent, _source, options = { override: false }) {
|
|
570
597
|
const existing = await gatherExistingContent(targetDir);
|
|
598
|
+
const markerOptions = options.markerPrefix ? { prefix: options.markerPrefix } : void 0;
|
|
571
599
|
const contentToMerge = [];
|
|
572
600
|
if (existing.agentsMd !== null && !options.override) {
|
|
573
|
-
const parsed = parseAgentsMd(existing.agentsMd);
|
|
601
|
+
const parsed = parseAgentsMd(existing.agentsMd, markerOptions);
|
|
574
602
|
if (parsed.hasMarkers) {
|
|
575
603
|
const repoContent2 = extractRepoBlockContent(parsed);
|
|
576
604
|
if (repoContent2) {
|
|
@@ -589,7 +617,7 @@ async function mergeAgentsMd(targetDir, globalContent, _source, options = { over
|
|
|
589
617
|
}
|
|
590
618
|
}
|
|
591
619
|
const repoContent = contentToMerge.length > 0 ? contentToMerge.join("\n\n") : null;
|
|
592
|
-
const content = buildAgentsMd(globalContent, repoContent, {});
|
|
620
|
+
const content = buildAgentsMd(globalContent, repoContent, {}, markerOptions);
|
|
593
621
|
const merged = !options.override && (existing.agentsMd !== null || existing.claudeMd !== null);
|
|
594
622
|
const preservedRepoContent = contentToMerge.length > 0;
|
|
595
623
|
return {
|
|
@@ -676,9 +704,11 @@ function getTargetConfig(target) {
|
|
|
676
704
|
|
|
677
705
|
// src/core/sync.ts
|
|
678
706
|
async function sync(targetDir, resolvedSource, options = { override: false, targets: ["claude"] }) {
|
|
707
|
+
const markerPrefix = resolvedSource.markerPrefix;
|
|
679
708
|
const globalContent = await fs5.readFile(resolvedSource.agentsMdPath, "utf-8");
|
|
680
709
|
const mergeResult = await mergeAgentsMd(targetDir, globalContent, resolvedSource.source, {
|
|
681
|
-
override: options.override
|
|
710
|
+
override: options.override,
|
|
711
|
+
markerPrefix
|
|
682
712
|
});
|
|
683
713
|
await writeAgentsMd(targetDir, mergeResult.content);
|
|
684
714
|
const skillDirs = await fg("*/", {
|
|
@@ -707,7 +737,8 @@ async function sync(targetDir, resolvedSource, options = { override: false, targ
|
|
|
707
737
|
targetDir,
|
|
708
738
|
resolvedSource.skillsPath,
|
|
709
739
|
skillNames,
|
|
710
|
-
config
|
|
740
|
+
config,
|
|
741
|
+
markerPrefix
|
|
711
742
|
);
|
|
712
743
|
totalCopied += skillsCopied;
|
|
713
744
|
let instructionsResult;
|
|
@@ -735,7 +766,8 @@ async function sync(targetDir, resolvedSource, options = { override: false, targ
|
|
|
735
766
|
source: resolvedSource.source,
|
|
736
767
|
globalBlockContent: globalContent,
|
|
737
768
|
skills: skillNames,
|
|
738
|
-
targets: options.targets
|
|
769
|
+
targets: options.targets,
|
|
770
|
+
markerPrefix
|
|
739
771
|
};
|
|
740
772
|
if (options.pinnedVersion) {
|
|
741
773
|
lockfileOptions.pinnedVersion = options.pinnedVersion;
|
|
@@ -755,18 +787,18 @@ async function sync(targetDir, resolvedSource, options = { override: false, targ
|
|
|
755
787
|
}
|
|
756
788
|
};
|
|
757
789
|
}
|
|
758
|
-
async function syncSkillsToTarget(targetDir, sourceSkillsPath, skillNames, config) {
|
|
790
|
+
async function syncSkillsToTarget(targetDir, sourceSkillsPath, skillNames, config, metadataPrefix) {
|
|
759
791
|
const targetSkillsPath = path5.join(targetDir, config.dir, "skills");
|
|
760
792
|
let copied = 0;
|
|
761
793
|
for (const skillName of skillNames) {
|
|
762
794
|
const sourceDir = path5.join(sourceSkillsPath, skillName);
|
|
763
795
|
const targetSkillDir = path5.join(targetSkillsPath, skillName);
|
|
764
|
-
const filesCopied = await copySkillDirectory(sourceDir, targetSkillDir);
|
|
796
|
+
const filesCopied = await copySkillDirectory(sourceDir, targetSkillDir, metadataPrefix);
|
|
765
797
|
copied += filesCopied;
|
|
766
798
|
}
|
|
767
799
|
return copied;
|
|
768
800
|
}
|
|
769
|
-
async function copySkillDirectory(sourceDir, targetDir) {
|
|
801
|
+
async function copySkillDirectory(sourceDir, targetDir, metadataPrefix) {
|
|
770
802
|
await fs5.mkdir(targetDir, { recursive: true });
|
|
771
803
|
const entries = await fs5.readdir(sourceDir, { withFileTypes: true });
|
|
772
804
|
let copied = 0;
|
|
@@ -774,10 +806,10 @@ async function copySkillDirectory(sourceDir, targetDir) {
|
|
|
774
806
|
const sourcePath = path5.join(sourceDir, entry.name);
|
|
775
807
|
const targetPath = path5.join(targetDir, entry.name);
|
|
776
808
|
if (entry.isDirectory()) {
|
|
777
|
-
copied += await copySkillDirectory(sourcePath, targetPath);
|
|
809
|
+
copied += await copySkillDirectory(sourcePath, targetPath, metadataPrefix);
|
|
778
810
|
} else if (entry.name === "SKILL.md") {
|
|
779
811
|
const content = await fs5.readFile(sourcePath, "utf-8");
|
|
780
|
-
const contentWithMetadata = addManagedMetadata(content);
|
|
812
|
+
const contentWithMetadata = addManagedMetadata(content, { metadataPrefix });
|
|
781
813
|
await fs5.writeFile(targetPath, contentWithMetadata, "utf-8");
|
|
782
814
|
copied++;
|
|
783
815
|
} else {
|
|
@@ -817,9 +849,10 @@ async function getSyncStatus(targetDir) {
|
|
|
817
849
|
function findOrphanedSkills(previousSkills, currentSkills) {
|
|
818
850
|
return previousSkills.filter((skill) => !currentSkills.includes(skill));
|
|
819
851
|
}
|
|
820
|
-
async function deleteOrphanedSkills(targetDir, orphanedSkills, targets, previouslyTrackedSkills) {
|
|
852
|
+
async function deleteOrphanedSkills(targetDir, orphanedSkills, targets, previouslyTrackedSkills, options = {}) {
|
|
821
853
|
const deleted = [];
|
|
822
854
|
const skipped = [];
|
|
855
|
+
const metadataOptions = options.metadataPrefix ? { metadataPrefix: options.metadataPrefix } : void 0;
|
|
823
856
|
for (const skillName of orphanedSkills) {
|
|
824
857
|
let wasDeleted = false;
|
|
825
858
|
for (const target of targets) {
|
|
@@ -832,15 +865,15 @@ async function deleteOrphanedSkills(targetDir, orphanedSkills, targets, previous
|
|
|
832
865
|
const skillMdPath = path5.join(skillDir, "SKILL.md");
|
|
833
866
|
try {
|
|
834
867
|
const content = await fs5.readFile(skillMdPath, "utf-8");
|
|
835
|
-
const { isManaged, hasManualChanges } = await import("./skill-metadata-
|
|
836
|
-
if (!isManaged(content)) {
|
|
868
|
+
const { isManaged, hasManualChanges } = await import("./skill-metadata-DK2WBJJ3.js");
|
|
869
|
+
if (!isManaged(content, metadataOptions)) {
|
|
837
870
|
if (!skipped.includes(skillName)) {
|
|
838
871
|
skipped.push(skillName);
|
|
839
872
|
}
|
|
840
873
|
continue;
|
|
841
874
|
}
|
|
842
875
|
const wasInPreviousLockfile = previouslyTrackedSkills.includes(skillName);
|
|
843
|
-
const isUnmodified = !hasManualChanges(content);
|
|
876
|
+
const isUnmodified = !hasManualChanges(content, metadataOptions);
|
|
844
877
|
if (!wasInPreviousLockfile && !isUnmodified) {
|
|
845
878
|
if (!skipped.includes(skillName)) {
|
|
846
879
|
skipped.push(skillName);
|
|
@@ -864,7 +897,7 @@ async function deleteOrphanedSkills(targetDir, orphanedSkills, targets, previous
|
|
|
864
897
|
}
|
|
865
898
|
|
|
866
899
|
// src/commands/shared.ts
|
|
867
|
-
import * as
|
|
900
|
+
import * as path12 from "path";
|
|
868
901
|
import * as prompts3 from "@clack/prompts";
|
|
869
902
|
import pc5 from "picocolors";
|
|
870
903
|
|
|
@@ -982,16 +1015,40 @@ async function installPreCommitHook(targetDir, config) {
|
|
|
982
1015
|
|
|
983
1016
|
// src/core/source.ts
|
|
984
1017
|
import { exec } from "child_process";
|
|
985
|
-
import * as
|
|
986
|
-
import * as
|
|
1018
|
+
import * as fs8 from "fs/promises";
|
|
1019
|
+
import * as path8 from "path";
|
|
987
1020
|
import { promisify } from "util";
|
|
988
1021
|
import { simpleGit } from "simple-git";
|
|
1022
|
+
|
|
1023
|
+
// src/config/loader.ts
|
|
1024
|
+
import * as fs7 from "fs/promises";
|
|
1025
|
+
import * as path7 from "path";
|
|
1026
|
+
import { parse as parseYaml } from "yaml";
|
|
1027
|
+
var CANONICAL_REPO_CONFIG = "agent-conf.yaml";
|
|
1028
|
+
async function loadCanonicalRepoConfig(basePath) {
|
|
1029
|
+
const configPath = path7.join(basePath, CANONICAL_REPO_CONFIG);
|
|
1030
|
+
try {
|
|
1031
|
+
const content = await fs7.readFile(configPath, "utf-8");
|
|
1032
|
+
const parsed = parseYaml(content);
|
|
1033
|
+
return CanonicalRepoConfigSchema.parse(parsed);
|
|
1034
|
+
} catch (error) {
|
|
1035
|
+
if (isNodeError(error) && error.code === "ENOENT") {
|
|
1036
|
+
return void 0;
|
|
1037
|
+
}
|
|
1038
|
+
throw new Error(`Failed to load ${CANONICAL_REPO_CONFIG}: ${error}`);
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
function isNodeError(error) {
|
|
1042
|
+
return error instanceof Error && "code" in error;
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
// src/core/source.ts
|
|
989
1046
|
var execAsync = promisify(exec);
|
|
990
1047
|
var DEFAULT_REF = "master";
|
|
991
1048
|
async function resolveLocalSource(options = {}) {
|
|
992
1049
|
let basePath;
|
|
993
1050
|
if (options.path) {
|
|
994
|
-
basePath =
|
|
1051
|
+
basePath = path8.resolve(options.path);
|
|
995
1052
|
} else {
|
|
996
1053
|
basePath = await findCanonicalRepo(process.cwd());
|
|
997
1054
|
}
|
|
@@ -1003,6 +1060,8 @@ async function resolveLocalSource(options = {}) {
|
|
|
1003
1060
|
commitSha = log2.latest?.hash;
|
|
1004
1061
|
} catch {
|
|
1005
1062
|
}
|
|
1063
|
+
const canonicalConfig = await loadCanonicalRepoConfig(basePath);
|
|
1064
|
+
const markerPrefix = canonicalConfig?.markers.prefix ?? "agent-conf";
|
|
1006
1065
|
const source = {
|
|
1007
1066
|
type: "local",
|
|
1008
1067
|
path: basePath,
|
|
@@ -1011,8 +1070,9 @@ async function resolveLocalSource(options = {}) {
|
|
|
1011
1070
|
return {
|
|
1012
1071
|
source,
|
|
1013
1072
|
basePath,
|
|
1014
|
-
agentsMdPath:
|
|
1015
|
-
skillsPath:
|
|
1073
|
+
agentsMdPath: path8.join(basePath, "instructions", "AGENTS.md"),
|
|
1074
|
+
skillsPath: path8.join(basePath, "skills"),
|
|
1075
|
+
markerPrefix
|
|
1016
1076
|
};
|
|
1017
1077
|
}
|
|
1018
1078
|
async function resolveGithubSource(options, tempDir) {
|
|
@@ -1021,6 +1081,8 @@ async function resolveGithubSource(options, tempDir) {
|
|
|
1021
1081
|
const clonedGit = simpleGit(tempDir);
|
|
1022
1082
|
const log2 = await clonedGit.log({ maxCount: 1 });
|
|
1023
1083
|
const commitSha = log2.latest?.hash ?? "";
|
|
1084
|
+
const canonicalConfig = await loadCanonicalRepoConfig(tempDir);
|
|
1085
|
+
const markerPrefix = canonicalConfig?.markers.prefix ?? "agent-conf";
|
|
1024
1086
|
const source = {
|
|
1025
1087
|
type: "github",
|
|
1026
1088
|
repository,
|
|
@@ -1030,8 +1092,9 @@ async function resolveGithubSource(options, tempDir) {
|
|
|
1030
1092
|
return {
|
|
1031
1093
|
source,
|
|
1032
1094
|
basePath: tempDir,
|
|
1033
|
-
agentsMdPath:
|
|
1034
|
-
skillsPath:
|
|
1095
|
+
agentsMdPath: path8.join(tempDir, "instructions", "AGENTS.md"),
|
|
1096
|
+
skillsPath: path8.join(tempDir, "skills"),
|
|
1097
|
+
markerPrefix
|
|
1035
1098
|
};
|
|
1036
1099
|
}
|
|
1037
1100
|
async function cloneRepository(repository, ref, tempDir) {
|
|
@@ -1056,19 +1119,19 @@ async function isGhAvailable() {
|
|
|
1056
1119
|
}
|
|
1057
1120
|
}
|
|
1058
1121
|
async function findCanonicalRepo(startDir) {
|
|
1059
|
-
let currentDir =
|
|
1060
|
-
const root =
|
|
1122
|
+
let currentDir = path8.resolve(startDir);
|
|
1123
|
+
const root = path8.parse(currentDir).root;
|
|
1061
1124
|
let checkDir = currentDir;
|
|
1062
1125
|
while (checkDir !== root) {
|
|
1063
1126
|
if (await isCanonicalRepo(checkDir)) {
|
|
1064
1127
|
return checkDir;
|
|
1065
1128
|
}
|
|
1066
|
-
checkDir =
|
|
1129
|
+
checkDir = path8.dirname(checkDir);
|
|
1067
1130
|
}
|
|
1068
|
-
currentDir =
|
|
1131
|
+
currentDir = path8.resolve(startDir);
|
|
1069
1132
|
while (currentDir !== root) {
|
|
1070
|
-
const parentDir =
|
|
1071
|
-
const siblingCanonicalRepo =
|
|
1133
|
+
const parentDir = path8.dirname(currentDir);
|
|
1134
|
+
const siblingCanonicalRepo = path8.join(parentDir, "agent-conf");
|
|
1072
1135
|
if (await isCanonicalRepo(siblingCanonicalRepo)) {
|
|
1073
1136
|
return siblingCanonicalRepo;
|
|
1074
1137
|
}
|
|
@@ -1080,15 +1143,15 @@ async function findCanonicalRepo(startDir) {
|
|
|
1080
1143
|
}
|
|
1081
1144
|
async function isCanonicalRepo(dir) {
|
|
1082
1145
|
try {
|
|
1083
|
-
const stat4 = await
|
|
1146
|
+
const stat4 = await fs8.stat(dir).catch(() => null);
|
|
1084
1147
|
if (!stat4?.isDirectory()) {
|
|
1085
1148
|
return false;
|
|
1086
1149
|
}
|
|
1087
|
-
const instructionsPath =
|
|
1088
|
-
const skillsPath =
|
|
1150
|
+
const instructionsPath = path8.join(dir, "instructions", "AGENTS.md");
|
|
1151
|
+
const skillsPath = path8.join(dir, "skills");
|
|
1089
1152
|
const [instructionsExists, skillsExists] = await Promise.all([
|
|
1090
|
-
|
|
1091
|
-
|
|
1153
|
+
fs8.access(instructionsPath).then(() => true).catch(() => false),
|
|
1154
|
+
fs8.access(skillsPath).then(() => true).catch(() => false)
|
|
1092
1155
|
]);
|
|
1093
1156
|
if (!instructionsExists || !skillsExists) {
|
|
1094
1157
|
return false;
|
|
@@ -1110,11 +1173,11 @@ async function isCanonicalRepo(dir) {
|
|
|
1110
1173
|
}
|
|
1111
1174
|
}
|
|
1112
1175
|
async function validateCanonicalRepo(basePath) {
|
|
1113
|
-
const agentsMdPath =
|
|
1114
|
-
const skillsPath =
|
|
1176
|
+
const agentsMdPath = path8.join(basePath, "instructions", "AGENTS.md");
|
|
1177
|
+
const skillsPath = path8.join(basePath, "skills");
|
|
1115
1178
|
const [agentsMdExists, skillsExists] = await Promise.all([
|
|
1116
|
-
|
|
1117
|
-
|
|
1179
|
+
fs8.access(agentsMdPath).then(() => true).catch(() => false),
|
|
1180
|
+
fs8.access(skillsPath).then(() => true).catch(() => false)
|
|
1118
1181
|
]);
|
|
1119
1182
|
if (!agentsMdExists) {
|
|
1120
1183
|
throw new Error(`Invalid canonical repository: missing instructions/AGENTS.md at ${basePath}`);
|
|
@@ -1233,8 +1296,8 @@ function compareVersions(a, b) {
|
|
|
1233
1296
|
}
|
|
1234
1297
|
|
|
1235
1298
|
// src/core/workflows.ts
|
|
1236
|
-
import * as
|
|
1237
|
-
import * as
|
|
1299
|
+
import * as fs9 from "fs/promises";
|
|
1300
|
+
import * as path9 from "path";
|
|
1238
1301
|
var DEFAULT_CLI_NAME2 = "agent-conf";
|
|
1239
1302
|
var WORKFLOWS_DIR = ".github/workflows";
|
|
1240
1303
|
function getWorkflowConfig(sourceRepo, config) {
|
|
@@ -1263,10 +1326,10 @@ function getWorkflowFiles(config) {
|
|
|
1263
1326
|
];
|
|
1264
1327
|
}
|
|
1265
1328
|
function getWorkflowsDir(repoRoot) {
|
|
1266
|
-
return
|
|
1329
|
+
return path9.join(repoRoot, WORKFLOWS_DIR);
|
|
1267
1330
|
}
|
|
1268
1331
|
function getWorkflowPath(repoRoot, filename) {
|
|
1269
|
-
return
|
|
1332
|
+
return path9.join(repoRoot, WORKFLOWS_DIR, filename);
|
|
1270
1333
|
}
|
|
1271
1334
|
function generateSyncWorkflow(versionRef, config) {
|
|
1272
1335
|
const { sourceRepo, cliName, secretName } = config;
|
|
@@ -1356,13 +1419,13 @@ function generateWorkflow(workflow, versionRef, config) {
|
|
|
1356
1419
|
}
|
|
1357
1420
|
async function ensureWorkflowsDir(repoRoot) {
|
|
1358
1421
|
const dir = getWorkflowsDir(repoRoot);
|
|
1359
|
-
await
|
|
1422
|
+
await fs9.mkdir(dir, { recursive: true });
|
|
1360
1423
|
}
|
|
1361
1424
|
async function writeWorkflow(repoRoot, workflow, versionRef, config) {
|
|
1362
1425
|
await ensureWorkflowsDir(repoRoot);
|
|
1363
1426
|
const filePath = getWorkflowPath(repoRoot, workflow.filename);
|
|
1364
1427
|
const content = generateWorkflow(workflow, versionRef, config);
|
|
1365
|
-
await
|
|
1428
|
+
await fs9.writeFile(filePath, content, "utf-8");
|
|
1366
1429
|
}
|
|
1367
1430
|
async function syncWorkflows(repoRoot, versionRef, sourceRepo, resolvedConfig) {
|
|
1368
1431
|
const config = getWorkflowConfig(sourceRepo, resolvedConfig);
|
|
@@ -1377,7 +1440,7 @@ async function syncWorkflows(repoRoot, versionRef, sourceRepo, resolvedConfig) {
|
|
|
1377
1440
|
const expectedContent = generateWorkflow(workflow, versionRef, config);
|
|
1378
1441
|
let existingContent = null;
|
|
1379
1442
|
try {
|
|
1380
|
-
existingContent = await
|
|
1443
|
+
existingContent = await fs9.readFile(filePath, "utf-8");
|
|
1381
1444
|
} catch {
|
|
1382
1445
|
}
|
|
1383
1446
|
if (existingContent === null) {
|
|
@@ -1394,15 +1457,15 @@ async function syncWorkflows(repoRoot, versionRef, sourceRepo, resolvedConfig) {
|
|
|
1394
1457
|
}
|
|
1395
1458
|
|
|
1396
1459
|
// src/utils/fs.ts
|
|
1397
|
-
import * as
|
|
1460
|
+
import * as fs10 from "fs/promises";
|
|
1398
1461
|
import * as os2 from "os";
|
|
1399
|
-
import * as
|
|
1462
|
+
import * as path10 from "path";
|
|
1400
1463
|
async function ensureDir(dirPath) {
|
|
1401
|
-
await
|
|
1464
|
+
await fs10.mkdir(dirPath, { recursive: true });
|
|
1402
1465
|
}
|
|
1403
1466
|
async function fileExists(filePath) {
|
|
1404
1467
|
try {
|
|
1405
|
-
await
|
|
1468
|
+
await fs10.access(filePath);
|
|
1406
1469
|
return true;
|
|
1407
1470
|
} catch {
|
|
1408
1471
|
return false;
|
|
@@ -1410,7 +1473,7 @@ async function fileExists(filePath) {
|
|
|
1410
1473
|
}
|
|
1411
1474
|
async function directoryExists(dirPath) {
|
|
1412
1475
|
try {
|
|
1413
|
-
const stat4 = await
|
|
1476
|
+
const stat4 = await fs10.stat(dirPath);
|
|
1414
1477
|
return stat4.isDirectory();
|
|
1415
1478
|
} catch {
|
|
1416
1479
|
return false;
|
|
@@ -1418,28 +1481,28 @@ async function directoryExists(dirPath) {
|
|
|
1418
1481
|
}
|
|
1419
1482
|
async function createTempDir(prefix = "agent-conf-") {
|
|
1420
1483
|
const tmpDir = os2.tmpdir();
|
|
1421
|
-
return
|
|
1484
|
+
return fs10.mkdtemp(path10.join(tmpDir, prefix));
|
|
1422
1485
|
}
|
|
1423
1486
|
async function removeTempDir(dirPath) {
|
|
1424
1487
|
try {
|
|
1425
|
-
await
|
|
1488
|
+
await fs10.rm(dirPath, { recursive: true, force: true });
|
|
1426
1489
|
} catch {
|
|
1427
1490
|
}
|
|
1428
1491
|
}
|
|
1429
1492
|
function resolvePath(inputPath) {
|
|
1430
1493
|
if (inputPath.startsWith("~")) {
|
|
1431
|
-
return
|
|
1494
|
+
return path10.join(os2.homedir(), inputPath.slice(1));
|
|
1432
1495
|
}
|
|
1433
|
-
return
|
|
1496
|
+
return path10.resolve(inputPath);
|
|
1434
1497
|
}
|
|
1435
1498
|
|
|
1436
1499
|
// src/utils/git.ts
|
|
1437
|
-
import * as
|
|
1438
|
-
import * as
|
|
1500
|
+
import * as fs11 from "fs/promises";
|
|
1501
|
+
import * as path11 from "path";
|
|
1439
1502
|
import { simpleGit as simpleGit2 } from "simple-git";
|
|
1440
1503
|
async function directoryExistsForGit(dir) {
|
|
1441
1504
|
try {
|
|
1442
|
-
const stat4 = await
|
|
1505
|
+
const stat4 = await fs11.stat(dir);
|
|
1443
1506
|
return stat4.isDirectory();
|
|
1444
1507
|
} catch {
|
|
1445
1508
|
return false;
|
|
@@ -1466,7 +1529,7 @@ async function getGitProjectName(dir) {
|
|
|
1466
1529
|
if (!gitRoot) {
|
|
1467
1530
|
return null;
|
|
1468
1531
|
}
|
|
1469
|
-
return
|
|
1532
|
+
return path11.basename(gitRoot);
|
|
1470
1533
|
}
|
|
1471
1534
|
async function isGitRoot(dir) {
|
|
1472
1535
|
if (!await directoryExistsForGit(dir)) {
|
|
@@ -1477,11 +1540,11 @@ async function isGitRoot(dir) {
|
|
|
1477
1540
|
return false;
|
|
1478
1541
|
}
|
|
1479
1542
|
try {
|
|
1480
|
-
const realDir = await
|
|
1481
|
-
const realGitRoot = await
|
|
1543
|
+
const realDir = await fs11.realpath(dir);
|
|
1544
|
+
const realGitRoot = await fs11.realpath(gitRoot);
|
|
1482
1545
|
return realDir === realGitRoot;
|
|
1483
1546
|
} catch {
|
|
1484
|
-
return
|
|
1547
|
+
return path11.resolve(dir) === path11.resolve(gitRoot);
|
|
1485
1548
|
}
|
|
1486
1549
|
}
|
|
1487
1550
|
async function getGitOrganization(dir) {
|
|
@@ -1790,7 +1853,7 @@ async function performSync(options) {
|
|
|
1790
1853
|
console.log();
|
|
1791
1854
|
console.log(pc5.bold("Sync complete:"));
|
|
1792
1855
|
console.log();
|
|
1793
|
-
const agentsMdPath = formatPath(
|
|
1856
|
+
const agentsMdPath = formatPath(path12.join(targetDir, "AGENTS.md"));
|
|
1794
1857
|
if (result.agentsMd.merged) {
|
|
1795
1858
|
const label = context.commandName === "sync" ? "(updated)" : "(merged)";
|
|
1796
1859
|
console.log(` ${pc5.green("+")} ${agentsMdPath} ${pc5.dim(label)}`);
|
|
@@ -1800,7 +1863,7 @@ async function performSync(options) {
|
|
|
1800
1863
|
for (const targetResult of result.targets) {
|
|
1801
1864
|
const config = getTargetConfig(targetResult.target);
|
|
1802
1865
|
if (config.instructionsFile) {
|
|
1803
|
-
const instructionsPath = targetResult.instructionsMd.location === "root" ? formatPath(
|
|
1866
|
+
const instructionsPath = targetResult.instructionsMd.location === "root" ? formatPath(path12.join(targetDir, config.instructionsFile)) : formatPath(path12.join(targetDir, config.dir, config.instructionsFile));
|
|
1804
1867
|
if (targetResult.instructionsMd.created) {
|
|
1805
1868
|
console.log(` ${pc5.green("+")} ${instructionsPath} ${pc5.dim("(created)")}`);
|
|
1806
1869
|
} else if (targetResult.instructionsMd.updated) {
|
|
@@ -1810,13 +1873,13 @@ async function performSync(options) {
|
|
|
1810
1873
|
console.log(` ${pc5.dim("-")} ${instructionsPath} ${pc5.dim("(unchanged)")}`);
|
|
1811
1874
|
}
|
|
1812
1875
|
}
|
|
1813
|
-
const skillsPath = formatPath(
|
|
1876
|
+
const skillsPath = formatPath(path12.join(targetDir, config.dir, "skills"));
|
|
1814
1877
|
console.log(
|
|
1815
1878
|
` ${pc5.green("+")} ${skillsPath}/ ${pc5.dim(`(${result.skills.synced.length} skills, ${targetResult.skills.copied} files)`)}`
|
|
1816
1879
|
);
|
|
1817
1880
|
if (orphanResult.deleted.length > 0) {
|
|
1818
1881
|
for (const skill of orphanResult.deleted) {
|
|
1819
|
-
const orphanPath = formatPath(
|
|
1882
|
+
const orphanPath = formatPath(path12.join(targetDir, config.dir, "skills", skill));
|
|
1820
1883
|
console.log(
|
|
1821
1884
|
` ${pc5.red("-")} ${orphanPath}/ ${pc5.dim("(removed - no longer in source)")}`
|
|
1822
1885
|
);
|
|
@@ -1824,28 +1887,28 @@ async function performSync(options) {
|
|
|
1824
1887
|
}
|
|
1825
1888
|
if (orphanResult.skipped.length > 0) {
|
|
1826
1889
|
for (const skill of orphanResult.skipped) {
|
|
1827
|
-
const orphanPath = formatPath(
|
|
1890
|
+
const orphanPath = formatPath(path12.join(targetDir, config.dir, "skills", skill));
|
|
1828
1891
|
console.log(` ${pc5.yellow("!")} ${orphanPath}/ ${pc5.dim("(orphaned but skipped)")}`);
|
|
1829
1892
|
}
|
|
1830
1893
|
}
|
|
1831
1894
|
}
|
|
1832
1895
|
if (workflowResult) {
|
|
1833
1896
|
for (const filename of workflowResult.created) {
|
|
1834
|
-
const workflowPath = formatPath(
|
|
1897
|
+
const workflowPath = formatPath(path12.join(targetDir, ".github/workflows", filename));
|
|
1835
1898
|
console.log(` ${pc5.green("+")} ${workflowPath} ${pc5.dim("(created)")}`);
|
|
1836
1899
|
}
|
|
1837
1900
|
for (const filename of workflowResult.updated) {
|
|
1838
|
-
const workflowPath = formatPath(
|
|
1901
|
+
const workflowPath = formatPath(path12.join(targetDir, ".github/workflows", filename));
|
|
1839
1902
|
console.log(` ${pc5.yellow("~")} ${workflowPath} ${pc5.dim("(updated)")}`);
|
|
1840
1903
|
}
|
|
1841
1904
|
for (const filename of workflowResult.unchanged) {
|
|
1842
|
-
const workflowPath = formatPath(
|
|
1905
|
+
const workflowPath = formatPath(path12.join(targetDir, ".github/workflows", filename));
|
|
1843
1906
|
console.log(` ${pc5.dim("-")} ${workflowPath} ${pc5.dim("(unchanged)")}`);
|
|
1844
1907
|
}
|
|
1845
1908
|
}
|
|
1846
|
-
const lockfilePath = formatPath(
|
|
1909
|
+
const lockfilePath = formatPath(path12.join(targetDir, ".agent-conf", "agent-conf.lock"));
|
|
1847
1910
|
console.log(` ${pc5.green("+")} ${lockfilePath}`);
|
|
1848
|
-
const hookPath = formatPath(
|
|
1911
|
+
const hookPath = formatPath(path12.join(targetDir, ".git/hooks/pre-commit"));
|
|
1849
1912
|
if (hookResult.installed) {
|
|
1850
1913
|
if (hookResult.alreadyExisted && !hookResult.wasUpdated) {
|
|
1851
1914
|
console.log(` ${pc5.dim("-")} ${hookPath} ${pc5.dim("(unchanged)")}`);
|
|
@@ -1915,8 +1978,8 @@ async function initCommand(options) {
|
|
|
1915
1978
|
}
|
|
1916
1979
|
|
|
1917
1980
|
// src/commands/init-canonical-repo.ts
|
|
1918
|
-
import * as
|
|
1919
|
-
import * as
|
|
1981
|
+
import * as fs12 from "fs/promises";
|
|
1982
|
+
import * as path13 from "path";
|
|
1920
1983
|
import * as prompts5 from "@clack/prompts";
|
|
1921
1984
|
import pc7 from "picocolors";
|
|
1922
1985
|
import { stringify as stringifyYaml } from "yaml";
|
|
@@ -2217,8 +2280,8 @@ async function initCanonicalRepoCommand(options) {
|
|
|
2217
2280
|
const logger = createLogger();
|
|
2218
2281
|
console.log();
|
|
2219
2282
|
prompts5.intro(pc7.bold("agent-conf init-canonical-repo"));
|
|
2220
|
-
const targetDir = options.dir ?
|
|
2221
|
-
const dirName =
|
|
2283
|
+
const targetDir = options.dir ? path13.resolve(options.dir) : process.cwd();
|
|
2284
|
+
const dirName = path13.basename(targetDir);
|
|
2222
2285
|
const cwd = process.cwd();
|
|
2223
2286
|
let isAtGitRoot = await isGitRoot(targetDir);
|
|
2224
2287
|
let gitProjectName = await getGitProjectName(targetDir);
|
|
@@ -2227,7 +2290,7 @@ async function initCanonicalRepoCommand(options) {
|
|
|
2227
2290
|
const cwdIsGitRoot = await isGitRoot(cwd);
|
|
2228
2291
|
const cwdGitProjectName = await getGitProjectName(cwd);
|
|
2229
2292
|
const cwdGitOrganization = await getGitOrganization(cwd);
|
|
2230
|
-
if (cwdIsGitRoot &&
|
|
2293
|
+
if (cwdIsGitRoot && path13.resolve(targetDir) === path13.resolve(cwd)) {
|
|
2231
2294
|
isAtGitRoot = true;
|
|
2232
2295
|
gitProjectName = cwdGitProjectName;
|
|
2233
2296
|
gitOrganization = cwdGitOrganization;
|
|
@@ -2246,7 +2309,7 @@ async function initCanonicalRepoCommand(options) {
|
|
|
2246
2309
|
}
|
|
2247
2310
|
const dirExists = await directoryExists(targetDir);
|
|
2248
2311
|
if (dirExists) {
|
|
2249
|
-
const configExists = await fileExists(
|
|
2312
|
+
const configExists = await fileExists(path13.join(targetDir, "agent-conf.yaml"));
|
|
2250
2313
|
if (configExists && !options.yes) {
|
|
2251
2314
|
const shouldContinue = await prompts5.confirm({
|
|
2252
2315
|
message: "This directory already has an agent-conf.yaml. Overwrite?",
|
|
@@ -2328,34 +2391,34 @@ async function initCanonicalRepoCommand(options) {
|
|
|
2328
2391
|
spinner.start();
|
|
2329
2392
|
try {
|
|
2330
2393
|
await ensureDir(resolvedOptions.targetDir);
|
|
2331
|
-
const instructionsDir =
|
|
2332
|
-
const skillsDir =
|
|
2333
|
-
const workflowsDir =
|
|
2394
|
+
const instructionsDir = path13.join(resolvedOptions.targetDir, "instructions");
|
|
2395
|
+
const skillsDir = path13.join(resolvedOptions.targetDir, "skills");
|
|
2396
|
+
const workflowsDir = path13.join(resolvedOptions.targetDir, ".github", "workflows");
|
|
2334
2397
|
await ensureDir(instructionsDir);
|
|
2335
2398
|
await ensureDir(skillsDir);
|
|
2336
2399
|
await ensureDir(workflowsDir);
|
|
2337
|
-
const configPath =
|
|
2338
|
-
await
|
|
2339
|
-
const agentsMdPath =
|
|
2340
|
-
await
|
|
2400
|
+
const configPath = path13.join(resolvedOptions.targetDir, "agent-conf.yaml");
|
|
2401
|
+
await fs12.writeFile(configPath, generateConfigYaml(resolvedOptions), "utf-8");
|
|
2402
|
+
const agentsMdPath = path13.join(instructionsDir, "AGENTS.md");
|
|
2403
|
+
await fs12.writeFile(agentsMdPath, generateAgentsMd(resolvedOptions), "utf-8");
|
|
2341
2404
|
if (resolvedOptions.includeExamples) {
|
|
2342
|
-
const exampleSkillDir =
|
|
2343
|
-
const referencesDir =
|
|
2405
|
+
const exampleSkillDir = path13.join(skillsDir, "example-skill");
|
|
2406
|
+
const referencesDir = path13.join(exampleSkillDir, "references");
|
|
2344
2407
|
await ensureDir(referencesDir);
|
|
2345
|
-
const skillMdPath =
|
|
2346
|
-
await
|
|
2347
|
-
const gitkeepPath =
|
|
2348
|
-
await
|
|
2408
|
+
const skillMdPath = path13.join(exampleSkillDir, "SKILL.md");
|
|
2409
|
+
await fs12.writeFile(skillMdPath, generateExampleSkillMd(), "utf-8");
|
|
2410
|
+
const gitkeepPath = path13.join(referencesDir, ".gitkeep");
|
|
2411
|
+
await fs12.writeFile(gitkeepPath, "", "utf-8");
|
|
2349
2412
|
}
|
|
2350
|
-
const syncWorkflowPath =
|
|
2351
|
-
const checkWorkflowPath =
|
|
2413
|
+
const syncWorkflowPath = path13.join(workflowsDir, "sync-reusable.yml");
|
|
2414
|
+
const checkWorkflowPath = path13.join(workflowsDir, "check-reusable.yml");
|
|
2352
2415
|
const repoFullName = resolvedOptions.organization ? `${resolvedOptions.organization}/${resolvedOptions.name}` : resolvedOptions.name;
|
|
2353
|
-
await
|
|
2416
|
+
await fs12.writeFile(
|
|
2354
2417
|
syncWorkflowPath,
|
|
2355
2418
|
generateSyncWorkflow2(repoFullName, resolvedOptions.markerPrefix),
|
|
2356
2419
|
"utf-8"
|
|
2357
2420
|
);
|
|
2358
|
-
await
|
|
2421
|
+
await fs12.writeFile(
|
|
2359
2422
|
checkWorkflowPath,
|
|
2360
2423
|
generateCheckWorkflow2(repoFullName, resolvedOptions.markerPrefix),
|
|
2361
2424
|
"utf-8"
|
|
@@ -2367,7 +2430,7 @@ async function initCanonicalRepoCommand(options) {
|
|
|
2367
2430
|
console.log(` ${pc7.green("+")} ${formatPath(agentsMdPath)}`);
|
|
2368
2431
|
if (resolvedOptions.includeExamples) {
|
|
2369
2432
|
console.log(
|
|
2370
|
-
` ${pc7.green("+")} ${formatPath(
|
|
2433
|
+
` ${pc7.green("+")} ${formatPath(path13.join(skillsDir, "example-skill/SKILL.md"))}`
|
|
2371
2434
|
);
|
|
2372
2435
|
}
|
|
2373
2436
|
console.log(` ${pc7.green("+")} ${formatPath(syncWorkflowPath)}`);
|
|
@@ -2398,7 +2461,7 @@ async function initCanonicalRepoCommand(options) {
|
|
|
2398
2461
|
}
|
|
2399
2462
|
|
|
2400
2463
|
// src/commands/status.ts
|
|
2401
|
-
import * as
|
|
2464
|
+
import * as path14 from "path";
|
|
2402
2465
|
import pc8 from "picocolors";
|
|
2403
2466
|
async function statusCommand(options = {}) {
|
|
2404
2467
|
const targetDir = process.cwd();
|
|
@@ -2451,7 +2514,7 @@ async function statusCommand(options = {}) {
|
|
|
2451
2514
|
}
|
|
2452
2515
|
console.log();
|
|
2453
2516
|
}
|
|
2454
|
-
const lockfilePath = formatPath(
|
|
2517
|
+
const lockfilePath = formatPath(path14.join(targetDir, ".agent-conf", "agent-conf.lock"));
|
|
2455
2518
|
console.log(pc8.dim(`Lock file: ${lockfilePath}`));
|
|
2456
2519
|
console.log(pc8.dim(`CLI version: ${lockfile.cli_version}`));
|
|
2457
2520
|
console.log();
|