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