aiblueprint-cli 1.4.62 → 1.4.64
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 +7 -1
- package/dist/cli.js +905 -355
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -33628,46 +33628,6 @@ async function mergeCodexConfigFile(sourceConfigPath, codexDir) {
|
|
|
33628
33628
|
// src/lib/configs-store.ts
|
|
33629
33629
|
var import_fs_extra7 = __toESM(require_lib4(), 1);
|
|
33630
33630
|
import path11 from "path";
|
|
33631
|
-
var COMMON_EXCLUDED_NAMES = new Set([
|
|
33632
|
-
".git",
|
|
33633
|
-
".DS_Store",
|
|
33634
|
-
"node_modules"
|
|
33635
|
-
]);
|
|
33636
|
-
var EXCLUDED_RUNTIME_PATHS = {
|
|
33637
|
-
".claude": new Set([
|
|
33638
|
-
"backups",
|
|
33639
|
-
"cache",
|
|
33640
|
-
"debug",
|
|
33641
|
-
"file-history",
|
|
33642
|
-
"logs",
|
|
33643
|
-
"output",
|
|
33644
|
-
"paste-cache",
|
|
33645
|
-
"plugins/cache",
|
|
33646
|
-
"projects",
|
|
33647
|
-
"session-env",
|
|
33648
|
-
"sessions",
|
|
33649
|
-
"stats-cache.json",
|
|
33650
|
-
"security.log"
|
|
33651
|
-
]),
|
|
33652
|
-
".codex": new Set([
|
|
33653
|
-
"archived_sessions",
|
|
33654
|
-
"browser/sessions",
|
|
33655
|
-
"cache",
|
|
33656
|
-
"log",
|
|
33657
|
-
"logs_2.sqlite",
|
|
33658
|
-
"logs_2.sqlite-shm",
|
|
33659
|
-
"logs_2.sqlite-wal",
|
|
33660
|
-
"models_cache.json",
|
|
33661
|
-
"plugins/cache",
|
|
33662
|
-
"sessions",
|
|
33663
|
-
"vendor_imports/skills-curated-cache.json"
|
|
33664
|
-
]),
|
|
33665
|
-
".agents": new Set([
|
|
33666
|
-
"cache",
|
|
33667
|
-
"logs",
|
|
33668
|
-
"sessions"
|
|
33669
|
-
])
|
|
33670
|
-
};
|
|
33671
33631
|
function getConfigStorePaths(rootDir) {
|
|
33672
33632
|
const baseDir = path11.join(rootDir, ".aiblueprint");
|
|
33673
33633
|
return {
|
|
@@ -33714,37 +33674,10 @@ async function hasContent(folderPath) {
|
|
|
33714
33674
|
const entries = await import_fs_extra7.default.readdir(folderPath);
|
|
33715
33675
|
return entries.some((entry) => entry !== ".DS_Store");
|
|
33716
33676
|
}
|
|
33717
|
-
function
|
|
33718
|
-
return relativePath.split(path11.sep).join("/");
|
|
33719
|
-
}
|
|
33720
|
-
function shouldCopyManagedPath(folderName, sourceRoot, sourcePath) {
|
|
33721
|
-
const basename = path11.basename(sourcePath);
|
|
33722
|
-
if (COMMON_EXCLUDED_NAMES.has(basename))
|
|
33723
|
-
return false;
|
|
33724
|
-
const relativePath = normalizeRelativePath(path11.relative(sourceRoot, sourcePath));
|
|
33725
|
-
if (!relativePath)
|
|
33726
|
-
return true;
|
|
33727
|
-
const excludedPaths = EXCLUDED_RUNTIME_PATHS[folderName];
|
|
33728
|
-
if (excludedPaths.has(relativePath))
|
|
33729
|
-
return false;
|
|
33730
|
-
for (const excludedPath of excludedPaths) {
|
|
33731
|
-
if (relativePath.startsWith(`${excludedPath}/`))
|
|
33732
|
-
return false;
|
|
33733
|
-
}
|
|
33734
|
-
return true;
|
|
33735
|
-
}
|
|
33736
|
-
async function copyManagedFolder(name, source, destination) {
|
|
33677
|
+
async function copyManagedFolder(source, destination) {
|
|
33737
33678
|
await import_fs_extra7.default.copy(source, destination, {
|
|
33738
33679
|
overwrite: true,
|
|
33739
|
-
dereference: false
|
|
33740
|
-
filter: async (src) => {
|
|
33741
|
-
try {
|
|
33742
|
-
const stat = await import_fs_extra7.default.lstat(src);
|
|
33743
|
-
return !stat.isSymbolicLink() && shouldCopyManagedPath(name, source, src);
|
|
33744
|
-
} catch {
|
|
33745
|
-
return true;
|
|
33746
|
-
}
|
|
33747
|
-
}
|
|
33680
|
+
dereference: false
|
|
33748
33681
|
});
|
|
33749
33682
|
}
|
|
33750
33683
|
async function writeMetadata(snapshotPath, metadata) {
|
|
@@ -33776,7 +33709,7 @@ async function snapshotByCopy(snapshotPath, folders, metadata) {
|
|
|
33776
33709
|
for (const folder of managedFolders(folders)) {
|
|
33777
33710
|
if (!await hasContent(folder.path))
|
|
33778
33711
|
continue;
|
|
33779
|
-
await copyManagedFolder(folder.
|
|
33712
|
+
await copyManagedFolder(folder.path, path11.join(snapshotPath, folder.name));
|
|
33780
33713
|
copied.push(folder.name);
|
|
33781
33714
|
}
|
|
33782
33715
|
if (copied.length === 0) {
|
|
@@ -33869,7 +33802,7 @@ async function restoreSnapshot(snapshotPath, folders) {
|
|
|
33869
33802
|
if (!await import_fs_extra7.default.pathExists(source))
|
|
33870
33803
|
continue;
|
|
33871
33804
|
await import_fs_extra7.default.ensureDir(path11.dirname(folder.path));
|
|
33872
|
-
await copyManagedFolder(
|
|
33805
|
+
await copyManagedFolder(source, folder.path);
|
|
33873
33806
|
restored.push(folder.name);
|
|
33874
33807
|
}
|
|
33875
33808
|
return restored;
|
|
@@ -35097,13 +35030,90 @@ function getInstructionFileCandidates(options) {
|
|
|
35097
35030
|
}
|
|
35098
35031
|
]);
|
|
35099
35032
|
}
|
|
35100
|
-
function
|
|
35101
|
-
|
|
35102
|
-
|
|
35103
|
-
|
|
35104
|
-
|
|
35105
|
-
|
|
35106
|
-
|
|
35033
|
+
function getRepositoryContainerCandidates(options) {
|
|
35034
|
+
const folders = resolveFolders(options);
|
|
35035
|
+
const cursorDir = path16.join(folders.rootDir, ".cursor");
|
|
35036
|
+
return uniqueByPath([
|
|
35037
|
+
...getContainerCandidates(options),
|
|
35038
|
+
{
|
|
35039
|
+
category: "rules",
|
|
35040
|
+
label: "agents-rules",
|
|
35041
|
+
path: path16.join(folders.agentsDir, "rules"),
|
|
35042
|
+
isDestination: true
|
|
35043
|
+
},
|
|
35044
|
+
{
|
|
35045
|
+
category: "rules",
|
|
35046
|
+
label: "claude-rules",
|
|
35047
|
+
path: path16.join(folders.claudeDir, "rules"),
|
|
35048
|
+
linkWhenMissing: true
|
|
35049
|
+
},
|
|
35050
|
+
{
|
|
35051
|
+
category: "rules",
|
|
35052
|
+
label: "codex-rules",
|
|
35053
|
+
path: path16.join(folders.codexDir, "rules"),
|
|
35054
|
+
linkWhenParentExists: true
|
|
35055
|
+
},
|
|
35056
|
+
{
|
|
35057
|
+
category: "rules",
|
|
35058
|
+
label: "cursor-rules",
|
|
35059
|
+
path: path16.join(cursorDir, "rules"),
|
|
35060
|
+
linkWhenParentExists: true
|
|
35061
|
+
},
|
|
35062
|
+
{
|
|
35063
|
+
category: "rules",
|
|
35064
|
+
label: "claude-memories",
|
|
35065
|
+
path: path16.join(folders.claudeDir, "memories"),
|
|
35066
|
+
linkSource: false
|
|
35067
|
+
},
|
|
35068
|
+
{
|
|
35069
|
+
category: "rules",
|
|
35070
|
+
label: "codex-memories",
|
|
35071
|
+
path: path16.join(folders.codexDir, "memories"),
|
|
35072
|
+
linkSource: false
|
|
35073
|
+
},
|
|
35074
|
+
{
|
|
35075
|
+
category: "rules",
|
|
35076
|
+
label: "cursor-memories",
|
|
35077
|
+
path: path16.join(cursorDir, "memories"),
|
|
35078
|
+
linkSource: false
|
|
35079
|
+
},
|
|
35080
|
+
{
|
|
35081
|
+
category: "rules",
|
|
35082
|
+
label: "claude-memory",
|
|
35083
|
+
path: path16.join(folders.claudeDir, "memory.md"),
|
|
35084
|
+
linkSource: false
|
|
35085
|
+
},
|
|
35086
|
+
{
|
|
35087
|
+
category: "rules",
|
|
35088
|
+
label: "codex-memory",
|
|
35089
|
+
path: path16.join(folders.codexDir, "memory.md"),
|
|
35090
|
+
linkSource: false
|
|
35091
|
+
},
|
|
35092
|
+
{
|
|
35093
|
+
category: "rules",
|
|
35094
|
+
label: "cursor-memory",
|
|
35095
|
+
path: path16.join(cursorDir, "memory.md"),
|
|
35096
|
+
linkSource: false
|
|
35097
|
+
},
|
|
35098
|
+
{
|
|
35099
|
+
category: "rules",
|
|
35100
|
+
label: "claude-memory-uppercase",
|
|
35101
|
+
path: path16.join(folders.claudeDir, "MEMORY.md"),
|
|
35102
|
+
linkSource: false
|
|
35103
|
+
},
|
|
35104
|
+
{
|
|
35105
|
+
category: "rules",
|
|
35106
|
+
label: "codex-memory-uppercase",
|
|
35107
|
+
path: path16.join(folders.codexDir, "MEMORY.md"),
|
|
35108
|
+
linkSource: false
|
|
35109
|
+
},
|
|
35110
|
+
{
|
|
35111
|
+
category: "rules",
|
|
35112
|
+
label: "cursor-memory-uppercase",
|
|
35113
|
+
path: path16.join(cursorDir, "MEMORY.md"),
|
|
35114
|
+
linkSource: false
|
|
35115
|
+
}
|
|
35116
|
+
]);
|
|
35107
35117
|
}
|
|
35108
35118
|
async function pathExistsOrSymlink(targetPath) {
|
|
35109
35119
|
const stat = await import_fs_extra12.default.lstat(targetPath).catch(() => null);
|
|
@@ -35148,6 +35158,73 @@ async function hashPath(targetPath) {
|
|
|
35148
35158
|
}
|
|
35149
35159
|
return hashString(`other:${stat.mode}:${stat.size}`);
|
|
35150
35160
|
}
|
|
35161
|
+
var TEXT_EXTENSIONS = new Set([
|
|
35162
|
+
".cjs",
|
|
35163
|
+
".js",
|
|
35164
|
+
".json",
|
|
35165
|
+
".jsonc",
|
|
35166
|
+
".md",
|
|
35167
|
+
".mdc",
|
|
35168
|
+
".mjs",
|
|
35169
|
+
".sh",
|
|
35170
|
+
".toml",
|
|
35171
|
+
".ts",
|
|
35172
|
+
".tsx",
|
|
35173
|
+
".txt",
|
|
35174
|
+
".yaml",
|
|
35175
|
+
".yml"
|
|
35176
|
+
]);
|
|
35177
|
+
var PORTABLE_PATH_REPLACEMENTS = [
|
|
35178
|
+
[/\.claude\/skills/g, ".agents/skills"],
|
|
35179
|
+
[/\.codex\/skills/g, ".agents/skills"],
|
|
35180
|
+
[/\.cursor\/skills-cursor/g, ".agents/skills"],
|
|
35181
|
+
[/\.cursor\/skills/g, ".agents/skills"],
|
|
35182
|
+
[/\.claude\/agents/g, ".agents/agents"],
|
|
35183
|
+
[/\.codex\/agents/g, ".agents/agents"],
|
|
35184
|
+
[/\.cursor\/agents/g, ".agents/agents"],
|
|
35185
|
+
[/\.claude\/rules/g, ".agents/rules"],
|
|
35186
|
+
[/\.codex\/rules/g, ".agents/rules"],
|
|
35187
|
+
[/\.cursor\/rules/g, ".agents/rules"],
|
|
35188
|
+
[/\.claude\/memories/g, ".agents/rules"],
|
|
35189
|
+
[/\.codex\/memories/g, ".agents/rules"],
|
|
35190
|
+
[/\.cursor\/memories/g, ".agents/rules"]
|
|
35191
|
+
];
|
|
35192
|
+
function normalizePortableText(content) {
|
|
35193
|
+
let normalized = content;
|
|
35194
|
+
for (const [pattern, replacement] of PORTABLE_PATH_REPLACEMENTS) {
|
|
35195
|
+
normalized = normalized.replace(pattern, replacement);
|
|
35196
|
+
}
|
|
35197
|
+
return normalized;
|
|
35198
|
+
}
|
|
35199
|
+
function isLikelyTextFile(filePath) {
|
|
35200
|
+
const ext = path16.extname(filePath).toLowerCase();
|
|
35201
|
+
if (TEXT_EXTENSIONS.has(ext))
|
|
35202
|
+
return true;
|
|
35203
|
+
return path16.basename(filePath) === "SKILL.md";
|
|
35204
|
+
}
|
|
35205
|
+
async function normalizePortableContent(targetPath) {
|
|
35206
|
+
const stat = await import_fs_extra12.default.lstat(targetPath).catch(() => null);
|
|
35207
|
+
if (!stat || stat.isSymbolicLink())
|
|
35208
|
+
return;
|
|
35209
|
+
if (stat.isDirectory()) {
|
|
35210
|
+
const entries = await import_fs_extra12.default.readdir(targetPath);
|
|
35211
|
+
for (const entry of entries) {
|
|
35212
|
+
if (IGNORED_ENTRY_NAMES2.has(entry))
|
|
35213
|
+
continue;
|
|
35214
|
+
await normalizePortableContent(path16.join(targetPath, entry));
|
|
35215
|
+
}
|
|
35216
|
+
return;
|
|
35217
|
+
}
|
|
35218
|
+
if (!stat.isFile() || !isLikelyTextFile(targetPath))
|
|
35219
|
+
return;
|
|
35220
|
+
const content = await import_fs_extra12.default.readFile(targetPath, "utf-8").catch(() => null);
|
|
35221
|
+
if (content === null || content.includes("\x00"))
|
|
35222
|
+
return;
|
|
35223
|
+
const normalized = normalizePortableText(content);
|
|
35224
|
+
if (normalized !== content) {
|
|
35225
|
+
await import_fs_extra12.default.writeFile(targetPath, normalized, "utf-8");
|
|
35226
|
+
}
|
|
35227
|
+
}
|
|
35151
35228
|
function suffixFromLabel(label) {
|
|
35152
35229
|
return label.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "source";
|
|
35153
35230
|
}
|
|
@@ -35196,7 +35273,7 @@ async function importCategoryEntries(category, candidates, destinationDir, resul
|
|
|
35196
35273
|
if (destinationRealPath && candidateRealPath && samePath(destinationRealPath, candidateRealPath)) {
|
|
35197
35274
|
continue;
|
|
35198
35275
|
}
|
|
35199
|
-
const entries = await
|
|
35276
|
+
const entries = await collectCandidateEntries(candidate).catch(() => null);
|
|
35200
35277
|
if (!entries) {
|
|
35201
35278
|
result.skipped.push({
|
|
35202
35279
|
category,
|
|
@@ -35206,9 +35283,9 @@ async function importCategoryEntries(category, candidates, destinationDir, resul
|
|
|
35206
35283
|
continue;
|
|
35207
35284
|
}
|
|
35208
35285
|
for (const entry of entries) {
|
|
35209
|
-
if (!
|
|
35286
|
+
if (!shouldCollectPath(category, entry.name, entry.path))
|
|
35210
35287
|
continue;
|
|
35211
|
-
const sourcePath =
|
|
35288
|
+
const sourcePath = entry.path;
|
|
35212
35289
|
const sourceHash = await hashPath(sourcePath);
|
|
35213
35290
|
const existingName = knownHashes.get(sourceHash);
|
|
35214
35291
|
if (existingName) {
|
|
@@ -35237,6 +35314,7 @@ async function importCategoryEntries(category, candidates, destinationDir, resul
|
|
|
35237
35314
|
dereference: false,
|
|
35238
35315
|
overwrite: false
|
|
35239
35316
|
});
|
|
35317
|
+
await normalizePortableContent(targetPath);
|
|
35240
35318
|
knownHashes.set(sourceHash, targetName);
|
|
35241
35319
|
result.imported.push({
|
|
35242
35320
|
category,
|
|
@@ -35247,6 +35325,41 @@ async function importCategoryEntries(category, candidates, destinationDir, resul
|
|
|
35247
35325
|
}
|
|
35248
35326
|
}
|
|
35249
35327
|
}
|
|
35328
|
+
async function collectCandidateEntries(candidate) {
|
|
35329
|
+
const stat = await import_fs_extra12.default.lstat(candidate.path);
|
|
35330
|
+
if (stat.isDirectory()) {
|
|
35331
|
+
const entries = await import_fs_extra12.default.readdir(candidate.path, { withFileTypes: true });
|
|
35332
|
+
return entries.map((entry) => ({
|
|
35333
|
+
name: entry.name,
|
|
35334
|
+
path: path16.join(candidate.path, entry.name)
|
|
35335
|
+
}));
|
|
35336
|
+
}
|
|
35337
|
+
if (stat.isSymbolicLink()) {
|
|
35338
|
+
const targetStat = await import_fs_extra12.default.stat(candidate.path).catch(() => null);
|
|
35339
|
+
if (targetStat?.isDirectory()) {
|
|
35340
|
+
const entries = await import_fs_extra12.default.readdir(candidate.path, { withFileTypes: true });
|
|
35341
|
+
return entries.map((entry) => ({
|
|
35342
|
+
name: entry.name,
|
|
35343
|
+
path: path16.join(candidate.path, entry.name)
|
|
35344
|
+
}));
|
|
35345
|
+
}
|
|
35346
|
+
}
|
|
35347
|
+
return [{
|
|
35348
|
+
name: path16.basename(candidate.path),
|
|
35349
|
+
path: candidate.path
|
|
35350
|
+
}];
|
|
35351
|
+
}
|
|
35352
|
+
async function shouldCollectPath(category, name, sourcePath) {
|
|
35353
|
+
if (IGNORED_ENTRY_NAMES2.has(name))
|
|
35354
|
+
return false;
|
|
35355
|
+
if (category === "skills" && name === ".cursor-managed-skills-manifest.json") {
|
|
35356
|
+
return true;
|
|
35357
|
+
}
|
|
35358
|
+
const stat = await import_fs_extra12.default.lstat(sourcePath).catch(() => null);
|
|
35359
|
+
if (!stat)
|
|
35360
|
+
return false;
|
|
35361
|
+
return stat.isFile() || stat.isDirectory() || stat.isSymbolicLink();
|
|
35362
|
+
}
|
|
35250
35363
|
function timestamp2(date = new Date) {
|
|
35251
35364
|
return date.toISOString().replace(/\.\d{3}Z$/, "").replace(/[:T]/g, "-");
|
|
35252
35365
|
}
|
|
@@ -35291,6 +35404,9 @@ async function shouldLinkMissingContainer(candidate) {
|
|
|
35291
35404
|
return import_fs_extra12.default.pathExists(path16.dirname(candidate.path));
|
|
35292
35405
|
}
|
|
35293
35406
|
async function linkContainer(candidate, destinationDir, result) {
|
|
35407
|
+
if (candidate.linkSource === false) {
|
|
35408
|
+
return;
|
|
35409
|
+
}
|
|
35294
35410
|
if (candidate.isDestination || samePath(candidate.path, destinationDir)) {
|
|
35295
35411
|
return;
|
|
35296
35412
|
}
|
|
@@ -35447,29 +35563,176 @@ async function linkInstructionFile(candidate, destinationPath, result) {
|
|
|
35447
35563
|
movedToBackup: backupTarget
|
|
35448
35564
|
});
|
|
35449
35565
|
}
|
|
35566
|
+
var RULES_INDEX_START = "<!-- AIBLUEPRINT:RULES:START -->";
|
|
35567
|
+
var RULES_INDEX_END = "<!-- AIBLUEPRINT:RULES:END -->";
|
|
35568
|
+
function titleFromRulePath(rulePath) {
|
|
35569
|
+
return path16.basename(rulePath, path16.extname(rulePath)).replace(/[-_]+/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
|
|
35570
|
+
}
|
|
35571
|
+
async function readRuleTitle(rulePath) {
|
|
35572
|
+
const content = await import_fs_extra12.default.readFile(rulePath, "utf-8").catch(() => "");
|
|
35573
|
+
const heading = content.match(/^#\s+(.+)$/m)?.[1]?.trim();
|
|
35574
|
+
return heading || titleFromRulePath(rulePath);
|
|
35575
|
+
}
|
|
35576
|
+
async function collectRuleIndexEntries(rulesDir, rootDir, currentDir = rulesDir) {
|
|
35577
|
+
const entries = await import_fs_extra12.default.readdir(currentDir, { withFileTypes: true }).catch(() => []);
|
|
35578
|
+
const rules = [];
|
|
35579
|
+
for (const entry of entries) {
|
|
35580
|
+
if (IGNORED_ENTRY_NAMES2.has(entry.name))
|
|
35581
|
+
continue;
|
|
35582
|
+
const entryPath = path16.join(currentDir, entry.name);
|
|
35583
|
+
if (entry.isDirectory()) {
|
|
35584
|
+
rules.push(...await collectRuleIndexEntries(rulesDir, rootDir, entryPath));
|
|
35585
|
+
continue;
|
|
35586
|
+
}
|
|
35587
|
+
if (!entry.isFile() && !entry.isSymbolicLink())
|
|
35588
|
+
continue;
|
|
35589
|
+
if (![".md", ".mdc"].includes(path16.extname(entry.name).toLowerCase()))
|
|
35590
|
+
continue;
|
|
35591
|
+
rules.push({
|
|
35592
|
+
title: await readRuleTitle(entryPath),
|
|
35593
|
+
relativePath: path16.relative(rootDir, entryPath)
|
|
35594
|
+
});
|
|
35595
|
+
}
|
|
35596
|
+
return rules.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
|
|
35597
|
+
}
|
|
35598
|
+
function stripGeneratedRulesIndex(content) {
|
|
35599
|
+
const start = content.indexOf(RULES_INDEX_START);
|
|
35600
|
+
const end = content.indexOf(RULES_INDEX_END);
|
|
35601
|
+
if (start === -1 || end === -1 || end < start) {
|
|
35602
|
+
return content.trimEnd();
|
|
35603
|
+
}
|
|
35604
|
+
const beforeStart = content.slice(0, start);
|
|
35605
|
+
const headingIndex = beforeStart.lastIndexOf(`
|
|
35606
|
+
## Rules`);
|
|
35607
|
+
const blockStart = headingIndex === -1 ? start : headingIndex + 1;
|
|
35608
|
+
return `${content.slice(0, blockStart).trimEnd()}
|
|
35609
|
+
${content.slice(end + RULES_INDEX_END.length).trimStart()}`.trimEnd();
|
|
35610
|
+
}
|
|
35611
|
+
function renderRulesIndexBlock(rules) {
|
|
35612
|
+
const lines = [
|
|
35613
|
+
"## Rules",
|
|
35614
|
+
"",
|
|
35615
|
+
"Detailed focused rules live in `.agents/rules/`. Read the relevant file before acting:",
|
|
35616
|
+
"",
|
|
35617
|
+
RULES_INDEX_START
|
|
35618
|
+
];
|
|
35619
|
+
if (rules.length === 0) {
|
|
35620
|
+
lines.push("- No repository rules found yet.");
|
|
35621
|
+
} else {
|
|
35622
|
+
for (const rule of rules) {
|
|
35623
|
+
lines.push(`- **${rule.title}** - [${rule.relativePath}](${rule.relativePath})`);
|
|
35624
|
+
}
|
|
35625
|
+
}
|
|
35626
|
+
lines.push(RULES_INDEX_END);
|
|
35627
|
+
return lines.join(`
|
|
35628
|
+
`);
|
|
35629
|
+
}
|
|
35630
|
+
async function readExistingInstructions(rootDir) {
|
|
35631
|
+
const agentsPath = path16.join(rootDir, "AGENTS.md");
|
|
35632
|
+
const claudePath = path16.join(rootDir, "CLAUDE.md");
|
|
35633
|
+
const agentsContent = await import_fs_extra12.default.readFile(agentsPath, "utf-8").catch(() => null);
|
|
35634
|
+
const claudeContent = await import_fs_extra12.default.readFile(claudePath, "utf-8").catch(() => null);
|
|
35635
|
+
if (agentsContent !== null && claudeContent !== null && agentsContent.trim() !== claudeContent.trim()) {
|
|
35636
|
+
return `${agentsContent.trimEnd()}
|
|
35637
|
+
|
|
35638
|
+
## Previous Claude Instructions
|
|
35639
|
+
|
|
35640
|
+
${claudeContent.trimStart()}`;
|
|
35641
|
+
}
|
|
35642
|
+
if (agentsContent !== null)
|
|
35643
|
+
return agentsContent;
|
|
35644
|
+
if (claudeContent !== null)
|
|
35645
|
+
return claudeContent;
|
|
35646
|
+
return `# Repository Instructions
|
|
35647
|
+
`;
|
|
35648
|
+
}
|
|
35649
|
+
async function copyPathToBackup(result, targetPath) {
|
|
35650
|
+
const stat = await import_fs_extra12.default.lstat(targetPath).catch(() => null);
|
|
35651
|
+
if (!stat)
|
|
35652
|
+
return null;
|
|
35653
|
+
const backupRoot = await ensureBackupPath(result);
|
|
35654
|
+
const backupTarget = path16.join(backupRoot, safeRelativePath(result.rootDir, targetPath));
|
|
35655
|
+
await import_fs_extra12.default.ensureDir(path16.dirname(backupTarget));
|
|
35656
|
+
await import_fs_extra12.default.copy(targetPath, backupTarget, {
|
|
35657
|
+
dereference: false,
|
|
35658
|
+
overwrite: false
|
|
35659
|
+
});
|
|
35660
|
+
return backupTarget;
|
|
35661
|
+
}
|
|
35662
|
+
async function replaceWithFileSymlink(sourcePath, targetPath) {
|
|
35663
|
+
await import_fs_extra12.default.ensureDir(path16.dirname(targetPath));
|
|
35664
|
+
const relativeSource = path16.relative(path16.dirname(targetPath), sourcePath) || path16.basename(sourcePath);
|
|
35665
|
+
await import_fs_extra12.default.symlink(relativeSource, targetPath, "file");
|
|
35666
|
+
}
|
|
35667
|
+
async function ensureClaudeInstructionSymlink(result, agentsPath, claudePath) {
|
|
35668
|
+
const agentsRealPath = await realPathIfPossible(agentsPath);
|
|
35669
|
+
const claudeStat = await import_fs_extra12.default.lstat(claudePath).catch(() => null);
|
|
35670
|
+
if (claudeStat?.isSymbolicLink()) {
|
|
35671
|
+
const claudeRealPath = await realPathIfPossible(claudePath);
|
|
35672
|
+
if (agentsRealPath && claudeRealPath && samePath(agentsRealPath, claudeRealPath)) {
|
|
35673
|
+
return;
|
|
35674
|
+
}
|
|
35675
|
+
}
|
|
35676
|
+
if (claudeStat) {
|
|
35677
|
+
await copyPathToBackup(result, claudePath);
|
|
35678
|
+
await import_fs_extra12.default.remove(claudePath);
|
|
35679
|
+
}
|
|
35680
|
+
await replaceWithFileSymlink(agentsPath, claudePath);
|
|
35681
|
+
}
|
|
35682
|
+
async function writeRepositoryInstructionIndex(result, folders) {
|
|
35683
|
+
const rulesDir = path16.join(folders.agentsDir, "rules");
|
|
35684
|
+
await import_fs_extra12.default.ensureDir(rulesDir);
|
|
35685
|
+
const rules = await collectRuleIndexEntries(rulesDir, folders.rootDir);
|
|
35686
|
+
const existing = stripGeneratedRulesIndex(await readExistingInstructions(folders.rootDir));
|
|
35687
|
+
const content = `${existing}
|
|
35688
|
+
|
|
35689
|
+
${renderRulesIndexBlock(rules)}
|
|
35690
|
+
`;
|
|
35691
|
+
const agentsPath = path16.join(folders.rootDir, "AGENTS.md");
|
|
35692
|
+
const claudePath = path16.join(folders.rootDir, "CLAUDE.md");
|
|
35693
|
+
const agentsStat = await import_fs_extra12.default.lstat(agentsPath).catch(() => null);
|
|
35694
|
+
if (agentsStat) {
|
|
35695
|
+
await copyPathToBackup(result, agentsPath);
|
|
35696
|
+
if (agentsStat.isSymbolicLink()) {
|
|
35697
|
+
await import_fs_extra12.default.remove(agentsPath);
|
|
35698
|
+
}
|
|
35699
|
+
}
|
|
35700
|
+
await import_fs_extra12.default.writeFile(agentsPath, content, "utf-8");
|
|
35701
|
+
await ensureClaudeInstructionSymlink(result, agentsPath, claudePath);
|
|
35702
|
+
result.instructionIndex = {
|
|
35703
|
+
agentsPath,
|
|
35704
|
+
claudePath,
|
|
35705
|
+
indexedRules: rules.map((rule) => rule.relativePath)
|
|
35706
|
+
};
|
|
35707
|
+
}
|
|
35450
35708
|
async function unifyAgentsConfiguration(options = {}) {
|
|
35709
|
+
const scope = options.scope ?? "global";
|
|
35451
35710
|
const folders = resolveFolders(options);
|
|
35452
|
-
const candidates = getContainerCandidates(options);
|
|
35453
35711
|
const instructionCandidates = getInstructionFileCandidates(options);
|
|
35712
|
+
const candidates = scope === "repository" ? getRepositoryContainerCandidates(options) : getContainerCandidates(options);
|
|
35454
35713
|
const result = {
|
|
35455
35714
|
rootDir: folders.rootDir,
|
|
35456
35715
|
agentsDir: folders.agentsDir,
|
|
35716
|
+
scope,
|
|
35457
35717
|
backupPath: null,
|
|
35458
35718
|
imported: [],
|
|
35459
35719
|
duplicates: [],
|
|
35460
35720
|
renamed: [],
|
|
35461
35721
|
linked: [],
|
|
35462
35722
|
alreadyLinked: [],
|
|
35463
|
-
skipped: []
|
|
35723
|
+
skipped: [],
|
|
35724
|
+
instructionIndex: null
|
|
35464
35725
|
};
|
|
35465
35726
|
const destinationByCategory = {
|
|
35466
35727
|
skills: path16.join(folders.agentsDir, "skills"),
|
|
35467
35728
|
agents: path16.join(folders.agentsDir, "agents"),
|
|
35468
|
-
instructions: path16.join(folders.agentsDir, "AGENTS.md")
|
|
35729
|
+
instructions: path16.join(folders.agentsDir, "AGENTS.md"),
|
|
35730
|
+
rules: path16.join(folders.agentsDir, "rules")
|
|
35469
35731
|
};
|
|
35470
35732
|
await import_fs_extra12.default.ensureDir(folders.agentsDir);
|
|
35471
35733
|
await importInstructionFiles(instructionCandidates, destinationByCategory.instructions, result);
|
|
35472
|
-
|
|
35734
|
+
const categories = scope === "repository" ? ["skills", "agents", "rules"] : ["skills", "agents"];
|
|
35735
|
+
for (const category of categories) {
|
|
35473
35736
|
await importCategoryEntries(category, candidates, destinationByCategory[category], result);
|
|
35474
35737
|
}
|
|
35475
35738
|
for (const candidate of candidates) {
|
|
@@ -35478,6 +35741,9 @@ async function unifyAgentsConfiguration(options = {}) {
|
|
|
35478
35741
|
for (const candidate of instructionCandidates) {
|
|
35479
35742
|
await linkInstructionFile(candidate, destinationByCategory.instructions, result);
|
|
35480
35743
|
}
|
|
35744
|
+
if (scope === "repository") {
|
|
35745
|
+
await writeRepositoryInstructionIndex(result, folders);
|
|
35746
|
+
}
|
|
35481
35747
|
return result;
|
|
35482
35748
|
}
|
|
35483
35749
|
|
|
@@ -35498,7 +35764,8 @@ async function agentsUnifyCommand(params = {}) {
|
|
|
35498
35764
|
console.log(source_default.blue.bold(`
|
|
35499
35765
|
AIBlueprint agents unify ${source_default.gray(`v${getVersion()}`)}
|
|
35500
35766
|
`));
|
|
35501
|
-
console.log(source_default.gray(
|
|
35767
|
+
console.log(source_default.gray(`Scope: ${params.scope ?? "global"}`));
|
|
35768
|
+
console.log(source_default.gray("Centralizing reusable agent configuration into .agents, then rendering Codex agents"));
|
|
35502
35769
|
const result = await unifyAgentsConfiguration(params);
|
|
35503
35770
|
const codexResult = await renderCodexAgentsFromMarkdown(params);
|
|
35504
35771
|
console.log(source_default.green(`
|
|
@@ -35507,7 +35774,14 @@ Unify complete`));
|
|
|
35507
35774
|
printCategorySummary(result, "instructions");
|
|
35508
35775
|
printCategorySummary(result, "skills");
|
|
35509
35776
|
printCategorySummary(result, "agents");
|
|
35777
|
+
if (result.scope === "repository") {
|
|
35778
|
+
printCategorySummary(result, "rules");
|
|
35779
|
+
}
|
|
35510
35780
|
console.log(source_default.gray(` codex agents: ${codexResult.rendered.length} rendered, ${codexResult.skipped.length} skipped`));
|
|
35781
|
+
if (result.instructionIndex) {
|
|
35782
|
+
console.log(source_default.gray(` rules index: ${result.instructionIndex.indexedRules.length} rules indexed in ${result.instructionIndex.agentsPath}`));
|
|
35783
|
+
console.log(source_default.gray(` Claude instructions: ${result.instructionIndex.claudePath}`));
|
|
35784
|
+
}
|
|
35511
35785
|
if (result.backupPath) {
|
|
35512
35786
|
console.log(source_default.gray(` Source backups: ${result.backupPath}`));
|
|
35513
35787
|
}
|
|
@@ -35553,6 +35827,359 @@ Codex agents render failed:`), error);
|
|
|
35553
35827
|
}
|
|
35554
35828
|
}
|
|
35555
35829
|
|
|
35830
|
+
// src/lib/session-unifier.ts
|
|
35831
|
+
var import_fs_extra14 = __toESM(require_lib4(), 1);
|
|
35832
|
+
import crypto2 from "crypto";
|
|
35833
|
+
import os15 from "os";
|
|
35834
|
+
import path18 from "path";
|
|
35835
|
+
|
|
35836
|
+
// src/lib/backup-utils.ts
|
|
35837
|
+
var import_fs_extra13 = __toESM(require_lib4(), 1);
|
|
35838
|
+
import path17 from "path";
|
|
35839
|
+
import os14 from "os";
|
|
35840
|
+
var BACKUP_BASE_DIR = path17.join(os14.homedir(), ".config", "aiblueprint", "backup");
|
|
35841
|
+
function getBackupDir() {
|
|
35842
|
+
return process.env.AIBLUEPRINT_BACKUP_DIR || BACKUP_BASE_DIR;
|
|
35843
|
+
}
|
|
35844
|
+
function formatDate(date) {
|
|
35845
|
+
const pad = (n) => n.toString().padStart(2, "0");
|
|
35846
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}-${pad(date.getHours())}-${pad(date.getMinutes())}-${pad(date.getSeconds())}`;
|
|
35847
|
+
}
|
|
35848
|
+
async function listBackups() {
|
|
35849
|
+
const backupBaseDir = getBackupDir();
|
|
35850
|
+
const exists = await import_fs_extra13.default.pathExists(backupBaseDir);
|
|
35851
|
+
if (!exists) {
|
|
35852
|
+
return [];
|
|
35853
|
+
}
|
|
35854
|
+
const entries = await import_fs_extra13.default.readdir(backupBaseDir, { withFileTypes: true });
|
|
35855
|
+
const backups = [];
|
|
35856
|
+
for (const entry of entries) {
|
|
35857
|
+
if (!entry.isDirectory())
|
|
35858
|
+
continue;
|
|
35859
|
+
const match = entry.name.match(/^(\d{4})-(\d{2})-(\d{2})-(\d{2})-(\d{2})-(\d{2})$/);
|
|
35860
|
+
if (!match)
|
|
35861
|
+
continue;
|
|
35862
|
+
const [, year, month, day, hour, minute, second] = match;
|
|
35863
|
+
const date = new Date(parseInt(year), parseInt(month) - 1, parseInt(day), parseInt(hour), parseInt(minute), parseInt(second));
|
|
35864
|
+
backups.push({
|
|
35865
|
+
name: entry.name,
|
|
35866
|
+
path: path17.join(backupBaseDir, entry.name),
|
|
35867
|
+
date
|
|
35868
|
+
});
|
|
35869
|
+
}
|
|
35870
|
+
return backups.sort((a, b) => b.date.getTime() - a.date.getTime());
|
|
35871
|
+
}
|
|
35872
|
+
var AGENTS_BACKUP_SUBDIR = ".agents";
|
|
35873
|
+
var CLAUDE_ITEMS = ["commands", "agents", "skills", "scripts", "settings.json"];
|
|
35874
|
+
var MANAGED_FOLDERS = [".claude", ".codex", ".agents"];
|
|
35875
|
+
async function copyForBackup(sourcePath, destPath) {
|
|
35876
|
+
await import_fs_extra13.default.copy(sourcePath, destPath, {
|
|
35877
|
+
overwrite: true,
|
|
35878
|
+
dereference: false
|
|
35879
|
+
});
|
|
35880
|
+
}
|
|
35881
|
+
async function hasMeaningfulContent(dir) {
|
|
35882
|
+
if (!await import_fs_extra13.default.pathExists(dir))
|
|
35883
|
+
return false;
|
|
35884
|
+
const files = await import_fs_extra13.default.readdir(dir);
|
|
35885
|
+
return files.some((f) => f !== ".DS_Store");
|
|
35886
|
+
}
|
|
35887
|
+
async function loadBackup(backupPath, claudeDir, codexDir, agentsDir) {
|
|
35888
|
+
const exists = await import_fs_extra13.default.pathExists(backupPath);
|
|
35889
|
+
if (!exists) {
|
|
35890
|
+
throw new Error(`Backup not found: ${backupPath}`);
|
|
35891
|
+
}
|
|
35892
|
+
const managedDestinations = {
|
|
35893
|
+
".claude": claudeDir,
|
|
35894
|
+
".codex": codexDir,
|
|
35895
|
+
".agents": agentsDir
|
|
35896
|
+
};
|
|
35897
|
+
let restoredManagedFolder = false;
|
|
35898
|
+
for (const folderName of MANAGED_FOLDERS) {
|
|
35899
|
+
const sourcePath = path17.join(backupPath, folderName);
|
|
35900
|
+
const destPath = managedDestinations[folderName];
|
|
35901
|
+
if (!destPath || !await import_fs_extra13.default.pathExists(sourcePath))
|
|
35902
|
+
continue;
|
|
35903
|
+
await import_fs_extra13.default.ensureDir(destPath);
|
|
35904
|
+
await copyForBackup(sourcePath, destPath);
|
|
35905
|
+
restoredManagedFolder = true;
|
|
35906
|
+
}
|
|
35907
|
+
if (!restoredManagedFolder) {
|
|
35908
|
+
await import_fs_extra13.default.ensureDir(claudeDir);
|
|
35909
|
+
for (const item of CLAUDE_ITEMS) {
|
|
35910
|
+
const sourcePath = path17.join(backupPath, item);
|
|
35911
|
+
const destPath = path17.join(claudeDir, item);
|
|
35912
|
+
if (await import_fs_extra13.default.pathExists(sourcePath)) {
|
|
35913
|
+
await copyForBackup(sourcePath, destPath);
|
|
35914
|
+
}
|
|
35915
|
+
}
|
|
35916
|
+
if (agentsDir) {
|
|
35917
|
+
const agentsBackupPath = path17.join(backupPath, AGENTS_BACKUP_SUBDIR);
|
|
35918
|
+
if (await import_fs_extra13.default.pathExists(agentsBackupPath)) {
|
|
35919
|
+
await import_fs_extra13.default.ensureDir(agentsDir);
|
|
35920
|
+
await copyForBackup(agentsBackupPath, agentsDir);
|
|
35921
|
+
}
|
|
35922
|
+
}
|
|
35923
|
+
}
|
|
35924
|
+
}
|
|
35925
|
+
async function createBackup(claudeDir, codexDir, agentsDir) {
|
|
35926
|
+
const claudeHasContent = await hasMeaningfulContent(claudeDir);
|
|
35927
|
+
const codexHasContent = codexDir ? await hasMeaningfulContent(codexDir) : false;
|
|
35928
|
+
const agentsHasContent = agentsDir ? await hasMeaningfulContent(agentsDir) : false;
|
|
35929
|
+
if (!claudeHasContent && !codexHasContent && !agentsHasContent) {
|
|
35930
|
+
return null;
|
|
35931
|
+
}
|
|
35932
|
+
const timestamp3 = formatDate(new Date);
|
|
35933
|
+
const backupPath = path17.join(getBackupDir(), timestamp3);
|
|
35934
|
+
await import_fs_extra13.default.ensureDir(backupPath);
|
|
35935
|
+
if (claudeHasContent) {
|
|
35936
|
+
await copyForBackup(claudeDir, path17.join(backupPath, ".claude"));
|
|
35937
|
+
}
|
|
35938
|
+
if (codexHasContent && codexDir) {
|
|
35939
|
+
await copyForBackup(codexDir, path17.join(backupPath, ".codex"));
|
|
35940
|
+
}
|
|
35941
|
+
if (agentsHasContent && agentsDir) {
|
|
35942
|
+
const destPath = path17.join(backupPath, AGENTS_BACKUP_SUBDIR);
|
|
35943
|
+
await copyForBackup(agentsDir, destPath);
|
|
35944
|
+
}
|
|
35945
|
+
return backupPath;
|
|
35946
|
+
}
|
|
35947
|
+
|
|
35948
|
+
// src/lib/session-unifier.ts
|
|
35949
|
+
var MANAGED_FOLDERS2 = [".claude", ".codex", ".agents"];
|
|
35950
|
+
var SESSION_PATHS = {
|
|
35951
|
+
".claude": ["projects", "sessions"],
|
|
35952
|
+
".codex": ["sessions", "archived_sessions", "browser/sessions"],
|
|
35953
|
+
".agents": ["sessions"]
|
|
35954
|
+
};
|
|
35955
|
+
async function listSnapshotSources(parentDir, type) {
|
|
35956
|
+
if (!await import_fs_extra14.default.pathExists(parentDir))
|
|
35957
|
+
return [];
|
|
35958
|
+
const entries = await import_fs_extra14.default.readdir(parentDir, { withFileTypes: true });
|
|
35959
|
+
return entries.filter((entry) => entry.isDirectory()).map((entry) => ({
|
|
35960
|
+
name: entry.name,
|
|
35961
|
+
path: path18.join(parentDir, entry.name),
|
|
35962
|
+
type
|
|
35963
|
+
}));
|
|
35964
|
+
}
|
|
35965
|
+
async function collectSnapshotSources(folders) {
|
|
35966
|
+
const storePaths = getConfigStorePaths(folders.rootDir);
|
|
35967
|
+
const sources = [
|
|
35968
|
+
...await listSnapshotSources(storePaths.configsDir, "config"),
|
|
35969
|
+
...await listSnapshotSources(storePaths.backupsDir, "backup")
|
|
35970
|
+
];
|
|
35971
|
+
if (path18.resolve(folders.rootDir) === os15.homedir()) {
|
|
35972
|
+
sources.push(...await listSnapshotSources(getBackupDir(), "legacy-backup"));
|
|
35973
|
+
}
|
|
35974
|
+
return sources.sort((a, b) => a.name.localeCompare(b.name));
|
|
35975
|
+
}
|
|
35976
|
+
async function snapshotFolderPath(snapshot, folder) {
|
|
35977
|
+
const managedPath = path18.join(snapshot.path, folder);
|
|
35978
|
+
if (await import_fs_extra14.default.pathExists(managedPath))
|
|
35979
|
+
return managedPath;
|
|
35980
|
+
if (snapshot.type === "legacy-backup") {
|
|
35981
|
+
if (folder === ".claude")
|
|
35982
|
+
return snapshot.path;
|
|
35983
|
+
const legacyAgentsPath = path18.join(snapshot.path, ".agents");
|
|
35984
|
+
if (folder === ".agents" && await import_fs_extra14.default.pathExists(legacyAgentsPath)) {
|
|
35985
|
+
return legacyAgentsPath;
|
|
35986
|
+
}
|
|
35987
|
+
}
|
|
35988
|
+
return null;
|
|
35989
|
+
}
|
|
35990
|
+
function sanitizeSourceTag(snapshot) {
|
|
35991
|
+
return `${snapshot.type}-${snapshot.name}`.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "snapshot";
|
|
35992
|
+
}
|
|
35993
|
+
function withSourceSuffix(targetPath, sourceTag, index) {
|
|
35994
|
+
const parsed = path18.parse(targetPath);
|
|
35995
|
+
const suffix = index === 1 ? sourceTag : `${sourceTag}-${index}`;
|
|
35996
|
+
if (parsed.ext && parsed.name) {
|
|
35997
|
+
return path18.join(parsed.dir, `${parsed.name}--${suffix}${parsed.ext}`);
|
|
35998
|
+
}
|
|
35999
|
+
return path18.join(parsed.dir, `${parsed.base}--${suffix}`);
|
|
36000
|
+
}
|
|
36001
|
+
async function uniqueConflictPath(targetPath, sourceTag) {
|
|
36002
|
+
let index = 1;
|
|
36003
|
+
while (true) {
|
|
36004
|
+
const candidate = withSourceSuffix(targetPath, sourceTag, index);
|
|
36005
|
+
if (!await import_fs_extra14.default.pathExists(candidate))
|
|
36006
|
+
return candidate;
|
|
36007
|
+
index++;
|
|
36008
|
+
}
|
|
36009
|
+
}
|
|
36010
|
+
function hashString2(value) {
|
|
36011
|
+
return crypto2.createHash("sha256").update(value).digest("hex");
|
|
36012
|
+
}
|
|
36013
|
+
async function hashPath2(targetPath) {
|
|
36014
|
+
const stat = await import_fs_extra14.default.lstat(targetPath);
|
|
36015
|
+
if (stat.isSymbolicLink()) {
|
|
36016
|
+
return hashString2(`symlink:${await import_fs_extra14.default.readlink(targetPath)}`);
|
|
36017
|
+
}
|
|
36018
|
+
if (stat.isFile()) {
|
|
36019
|
+
const hash = crypto2.createHash("sha256");
|
|
36020
|
+
hash.update("file:");
|
|
36021
|
+
hash.update(await import_fs_extra14.default.readFile(targetPath));
|
|
36022
|
+
return hash.digest("hex");
|
|
36023
|
+
}
|
|
36024
|
+
if (stat.isDirectory()) {
|
|
36025
|
+
const entries = (await import_fs_extra14.default.readdir(targetPath, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name));
|
|
36026
|
+
const hash = crypto2.createHash("sha256");
|
|
36027
|
+
hash.update("dir:");
|
|
36028
|
+
for (const entry of entries) {
|
|
36029
|
+
hash.update(entry.name);
|
|
36030
|
+
hash.update("\x00");
|
|
36031
|
+
hash.update(await hashPath2(path18.join(targetPath, entry.name)));
|
|
36032
|
+
hash.update("\x00");
|
|
36033
|
+
}
|
|
36034
|
+
return hash.digest("hex");
|
|
36035
|
+
}
|
|
36036
|
+
return hashString2(`other:${stat.mode}:${stat.size}`);
|
|
36037
|
+
}
|
|
36038
|
+
async function mergeSessionPath(params) {
|
|
36039
|
+
const {
|
|
36040
|
+
sourcePath,
|
|
36041
|
+
destinationPath,
|
|
36042
|
+
folder,
|
|
36043
|
+
sessionRoot,
|
|
36044
|
+
snapshot,
|
|
36045
|
+
sourceTag,
|
|
36046
|
+
result
|
|
36047
|
+
} = params;
|
|
36048
|
+
const sourceStat = await import_fs_extra14.default.lstat(sourcePath).catch(() => null);
|
|
36049
|
+
if (!sourceStat)
|
|
36050
|
+
return;
|
|
36051
|
+
const destinationStat = await import_fs_extra14.default.lstat(destinationPath).catch(() => null);
|
|
36052
|
+
if (sourceStat.isDirectory() && destinationStat?.isDirectory()) {
|
|
36053
|
+
const entries = await import_fs_extra14.default.readdir(sourcePath);
|
|
36054
|
+
await import_fs_extra14.default.ensureDir(destinationPath);
|
|
36055
|
+
for (const entry of entries) {
|
|
36056
|
+
await mergeSessionPath({
|
|
36057
|
+
sourcePath: path18.join(sourcePath, entry),
|
|
36058
|
+
destinationPath: path18.join(destinationPath, entry),
|
|
36059
|
+
folder,
|
|
36060
|
+
sessionRoot,
|
|
36061
|
+
snapshot,
|
|
36062
|
+
sourceTag,
|
|
36063
|
+
result
|
|
36064
|
+
});
|
|
36065
|
+
}
|
|
36066
|
+
return;
|
|
36067
|
+
}
|
|
36068
|
+
if (!destinationStat) {
|
|
36069
|
+
await import_fs_extra14.default.ensureDir(path18.dirname(destinationPath));
|
|
36070
|
+
await import_fs_extra14.default.copy(sourcePath, destinationPath, {
|
|
36071
|
+
overwrite: false,
|
|
36072
|
+
dereference: false
|
|
36073
|
+
});
|
|
36074
|
+
result.imported.push({
|
|
36075
|
+
folder,
|
|
36076
|
+
sessionRoot,
|
|
36077
|
+
from: sourcePath,
|
|
36078
|
+
to: destinationPath,
|
|
36079
|
+
snapshot: snapshot.name
|
|
36080
|
+
});
|
|
36081
|
+
return;
|
|
36082
|
+
}
|
|
36083
|
+
if (await hashPath2(sourcePath) === await hashPath2(destinationPath)) {
|
|
36084
|
+
result.duplicates.push({
|
|
36085
|
+
folder,
|
|
36086
|
+
sessionRoot,
|
|
36087
|
+
from: sourcePath,
|
|
36088
|
+
existing: destinationPath,
|
|
36089
|
+
snapshot: snapshot.name
|
|
36090
|
+
});
|
|
36091
|
+
return;
|
|
36092
|
+
}
|
|
36093
|
+
const conflictPath = await uniqueConflictPath(destinationPath, sourceTag);
|
|
36094
|
+
await import_fs_extra14.default.ensureDir(path18.dirname(conflictPath));
|
|
36095
|
+
await import_fs_extra14.default.copy(sourcePath, conflictPath, {
|
|
36096
|
+
overwrite: false,
|
|
36097
|
+
dereference: false
|
|
36098
|
+
});
|
|
36099
|
+
result.conflicts.push({
|
|
36100
|
+
folder,
|
|
36101
|
+
sessionRoot,
|
|
36102
|
+
from: sourcePath,
|
|
36103
|
+
to: conflictPath,
|
|
36104
|
+
snapshot: snapshot.name,
|
|
36105
|
+
reason: "Same session path with different content"
|
|
36106
|
+
});
|
|
36107
|
+
}
|
|
36108
|
+
async function unifySessionsFromSnapshots(options = {}) {
|
|
36109
|
+
const folders = resolveFolders(options);
|
|
36110
|
+
const snapshots = await collectSnapshotSources(folders);
|
|
36111
|
+
const destinationByFolder = {
|
|
36112
|
+
".claude": folders.claudeDir,
|
|
36113
|
+
".codex": folders.codexDir,
|
|
36114
|
+
".agents": folders.agentsDir
|
|
36115
|
+
};
|
|
36116
|
+
const result = {
|
|
36117
|
+
rootDir: folders.rootDir,
|
|
36118
|
+
scannedSnapshots: snapshots,
|
|
36119
|
+
imported: [],
|
|
36120
|
+
duplicates: [],
|
|
36121
|
+
conflicts: []
|
|
36122
|
+
};
|
|
36123
|
+
for (const snapshot of snapshots) {
|
|
36124
|
+
const sourceTag = sanitizeSourceTag(snapshot);
|
|
36125
|
+
for (const folder of MANAGED_FOLDERS2) {
|
|
36126
|
+
const sourceFolder = await snapshotFolderPath(snapshot, folder);
|
|
36127
|
+
if (!sourceFolder)
|
|
36128
|
+
continue;
|
|
36129
|
+
for (const sessionRoot of SESSION_PATHS[folder]) {
|
|
36130
|
+
const sourcePath = path18.join(sourceFolder, sessionRoot);
|
|
36131
|
+
if (!await import_fs_extra14.default.pathExists(sourcePath))
|
|
36132
|
+
continue;
|
|
36133
|
+
await mergeSessionPath({
|
|
36134
|
+
sourcePath,
|
|
36135
|
+
destinationPath: path18.join(destinationByFolder[folder], sessionRoot),
|
|
36136
|
+
folder,
|
|
36137
|
+
sessionRoot,
|
|
36138
|
+
snapshot,
|
|
36139
|
+
sourceTag,
|
|
36140
|
+
result
|
|
36141
|
+
});
|
|
36142
|
+
}
|
|
36143
|
+
}
|
|
36144
|
+
}
|
|
36145
|
+
return result;
|
|
36146
|
+
}
|
|
36147
|
+
|
|
36148
|
+
// src/commands/session-unify.ts
|
|
36149
|
+
function summarizeByFolder(entries) {
|
|
36150
|
+
const counts = new Map;
|
|
36151
|
+
for (const entry of entries) {
|
|
36152
|
+
counts.set(entry.folder, (counts.get(entry.folder) ?? 0) + 1);
|
|
36153
|
+
}
|
|
36154
|
+
if (counts.size === 0)
|
|
36155
|
+
return "none";
|
|
36156
|
+
return [...counts.entries()].map(([folder, count]) => `${folder}: ${count}`).join(", ");
|
|
36157
|
+
}
|
|
36158
|
+
async function sessionsUnifyCommand(params = {}) {
|
|
36159
|
+
try {
|
|
36160
|
+
console.log(source_default.blue("Unifying saved sessions from configs and backups..."));
|
|
36161
|
+
const result = await unifySessionsFromSnapshots(params);
|
|
36162
|
+
console.log(source_default.green("Session unify complete"));
|
|
36163
|
+
console.log(source_default.gray(` Snapshots scanned: ${result.scannedSnapshots.length}`));
|
|
36164
|
+
console.log(source_default.gray(` Imported: ${result.imported.length} (${summarizeByFolder(result.imported)})`));
|
|
36165
|
+
console.log(source_default.gray(` Duplicates skipped: ${result.duplicates.length}`));
|
|
36166
|
+
console.log(source_default.gray(` Conflicts preserved: ${result.conflicts.length}`));
|
|
36167
|
+
if (result.conflicts.length > 0) {
|
|
36168
|
+
console.log(source_default.yellow(`
|
|
36169
|
+
Conflicting session paths were copied with source suffixes:`));
|
|
36170
|
+
for (const conflict of result.conflicts.slice(0, 10)) {
|
|
36171
|
+
console.log(source_default.yellow(` ${conflict.to}`));
|
|
36172
|
+
}
|
|
36173
|
+
if (result.conflicts.length > 10) {
|
|
36174
|
+
console.log(source_default.yellow(` ...and ${result.conflicts.length - 10} more`));
|
|
36175
|
+
}
|
|
36176
|
+
}
|
|
36177
|
+
} catch (error) {
|
|
36178
|
+
console.error(source_default.red("Session unify failed:"), error);
|
|
36179
|
+
process.exit(1);
|
|
36180
|
+
}
|
|
36181
|
+
}
|
|
36182
|
+
|
|
35556
36183
|
// node_modules/@clack/core/dist/index.mjs
|
|
35557
36184
|
var import_sisteransi = __toESM(require_src(), 1);
|
|
35558
36185
|
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
@@ -36269,12 +36896,12 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
|
|
|
36269
36896
|
};
|
|
36270
36897
|
|
|
36271
36898
|
// src/commands/pro.ts
|
|
36272
|
-
import
|
|
36899
|
+
import path21 from "path";
|
|
36273
36900
|
|
|
36274
36901
|
// src/lib/pro-installer.ts
|
|
36275
|
-
var
|
|
36276
|
-
import
|
|
36277
|
-
import
|
|
36902
|
+
var import_fs_extra15 = __toESM(require_lib4(), 1);
|
|
36903
|
+
import os16 from "os";
|
|
36904
|
+
import path19 from "path";
|
|
36278
36905
|
import { exec as exec3 } from "child_process";
|
|
36279
36906
|
import { promisify as promisify2 } from "util";
|
|
36280
36907
|
var execAsync2 = promisify2(exec3);
|
|
@@ -36282,9 +36909,9 @@ var PREMIUM_REPO = "Melvynx/aiblueprint-cli-premium";
|
|
|
36282
36909
|
var PREMIUM_BRANCH = "main";
|
|
36283
36910
|
var CONFIG_FOLDER_CANDIDATES2 = ["agents-config", "ai-coding", "claude-code-config", "ai-config"];
|
|
36284
36911
|
function routePath(relativePath) {
|
|
36285
|
-
const segments = relativePath.split(
|
|
36912
|
+
const segments = relativePath.split(path19.sep);
|
|
36286
36913
|
const first = segments[0];
|
|
36287
|
-
const rest = segments.slice(1).join(
|
|
36914
|
+
const rest = segments.slice(1).join(path19.sep);
|
|
36288
36915
|
if (first === "claude-config") {
|
|
36289
36916
|
return { kind: "claude", relativePath: rest };
|
|
36290
36917
|
}
|
|
@@ -36300,7 +36927,7 @@ function routePath(relativePath) {
|
|
|
36300
36927
|
return { kind: "claude", relativePath };
|
|
36301
36928
|
}
|
|
36302
36929
|
function getCacheRepoDir() {
|
|
36303
|
-
return
|
|
36930
|
+
return path19.join(os16.homedir(), ".config", "aiblueprint", "pro-repos", "aiblueprint-cli-premium");
|
|
36304
36931
|
}
|
|
36305
36932
|
async function execGitWithAuth(command, token, repoUrl, cwd) {
|
|
36306
36933
|
const authenticatedUrl = `https://x-access-token:${token}@${repoUrl.replace(/^https?:\/\//, "")}`;
|
|
@@ -36314,21 +36941,21 @@ async function execGitWithAuth(command, token, repoUrl, cwd) {
|
|
|
36314
36941
|
async function cloneOrUpdateRepo(token) {
|
|
36315
36942
|
const cacheDir = getCacheRepoDir();
|
|
36316
36943
|
const repoUrl = `https://github.com/${PREMIUM_REPO}.git`;
|
|
36317
|
-
if (await
|
|
36944
|
+
if (await import_fs_extra15.default.pathExists(path19.join(cacheDir, ".git"))) {
|
|
36318
36945
|
try {
|
|
36319
36946
|
await execGitWithAuth("pull", token, repoUrl, cacheDir);
|
|
36320
36947
|
} catch (error) {
|
|
36321
|
-
await
|
|
36322
|
-
await
|
|
36948
|
+
await import_fs_extra15.default.remove(cacheDir);
|
|
36949
|
+
await import_fs_extra15.default.ensureDir(path19.dirname(cacheDir));
|
|
36323
36950
|
await execGitWithAuth(`clone ${repoUrl} ${cacheDir}`, token, repoUrl);
|
|
36324
36951
|
}
|
|
36325
36952
|
} else {
|
|
36326
|
-
await
|
|
36953
|
+
await import_fs_extra15.default.ensureDir(path19.dirname(cacheDir));
|
|
36327
36954
|
await execGitWithAuth(`clone ${repoUrl} ${cacheDir}`, token, repoUrl);
|
|
36328
36955
|
}
|
|
36329
36956
|
for (const candidate of CONFIG_FOLDER_CANDIDATES2) {
|
|
36330
|
-
const candidatePath =
|
|
36331
|
-
if (await
|
|
36957
|
+
const candidatePath = path19.join(cacheDir, candidate);
|
|
36958
|
+
if (await import_fs_extra15.default.pathExists(candidatePath)) {
|
|
36332
36959
|
return candidatePath;
|
|
36333
36960
|
}
|
|
36334
36961
|
}
|
|
@@ -36336,38 +36963,38 @@ async function cloneOrUpdateRepo(token) {
|
|
|
36336
36963
|
}
|
|
36337
36964
|
async function copyConfigFromCache(cacheConfigDir, dest, onProgress) {
|
|
36338
36965
|
const walk = async (dir, baseDir = dir) => {
|
|
36339
|
-
const entries = await
|
|
36966
|
+
const entries = await import_fs_extra15.default.readdir(dir, { withFileTypes: true });
|
|
36340
36967
|
for (const entry of entries) {
|
|
36341
36968
|
if (entry.name === ".DS_Store" || entry.name === "node_modules")
|
|
36342
36969
|
continue;
|
|
36343
|
-
const sourcePath =
|
|
36344
|
-
const relativePath =
|
|
36970
|
+
const sourcePath = path19.join(dir, entry.name);
|
|
36971
|
+
const relativePath = path19.relative(baseDir, sourcePath);
|
|
36345
36972
|
const route = routePath(relativePath);
|
|
36346
36973
|
if (route.kind === "skip")
|
|
36347
36974
|
continue;
|
|
36348
36975
|
if (route.kind === "agents-category") {
|
|
36349
|
-
if (relativePath.split(
|
|
36976
|
+
if (relativePath.split(path19.sep).length === 1) {
|
|
36350
36977
|
await copyAgentCategory(sourcePath, route.category, dest.agentsDir, dest.claudeDir, onProgress);
|
|
36351
36978
|
}
|
|
36352
36979
|
continue;
|
|
36353
36980
|
}
|
|
36354
36981
|
const targetBase = route.kind === "claude" ? dest.claudeDir : dest.codexDir;
|
|
36355
|
-
const targetPath =
|
|
36982
|
+
const targetPath = path19.join(targetBase, route.relativePath);
|
|
36356
36983
|
if (entry.isDirectory()) {
|
|
36357
|
-
await
|
|
36984
|
+
await import_fs_extra15.default.ensureDir(targetPath);
|
|
36358
36985
|
onProgress?.(relativePath, "directory");
|
|
36359
36986
|
await walk(sourcePath, baseDir);
|
|
36360
36987
|
} else if (route.kind === "codex" && route.relativePath === "config.toml") {
|
|
36361
36988
|
await mergeCodexConfigFile(sourcePath, dest.codexDir);
|
|
36362
36989
|
onProgress?.(relativePath, "file");
|
|
36363
36990
|
} else if (isTextFile(entry.name)) {
|
|
36364
|
-
const content = await
|
|
36991
|
+
const content = await import_fs_extra15.default.readFile(sourcePath, "utf-8");
|
|
36365
36992
|
const replaced = replaceClaudePathPlaceholder(content, dest.claudeDir);
|
|
36366
|
-
await
|
|
36367
|
-
await
|
|
36993
|
+
await import_fs_extra15.default.ensureDir(path19.dirname(targetPath));
|
|
36994
|
+
await import_fs_extra15.default.writeFile(targetPath, replaced, "utf-8");
|
|
36368
36995
|
onProgress?.(relativePath, "file");
|
|
36369
36996
|
} else {
|
|
36370
|
-
await
|
|
36997
|
+
await import_fs_extra15.default.copy(sourcePath, targetPath, { overwrite: true });
|
|
36371
36998
|
onProgress?.(relativePath, "file");
|
|
36372
36999
|
}
|
|
36373
37000
|
}
|
|
@@ -36375,21 +37002,21 @@ async function copyConfigFromCache(cacheConfigDir, dest, onProgress) {
|
|
|
36375
37002
|
await walk(cacheConfigDir);
|
|
36376
37003
|
}
|
|
36377
37004
|
async function copyAgentCategory(sourceCategoryDir, category, agentsDir, claudeDir, onProgress) {
|
|
36378
|
-
const agentsCategoryDir =
|
|
36379
|
-
await
|
|
36380
|
-
const entries = await
|
|
37005
|
+
const agentsCategoryDir = path19.join(agentsDir, category);
|
|
37006
|
+
await import_fs_extra15.default.ensureDir(agentsCategoryDir);
|
|
37007
|
+
const entries = await import_fs_extra15.default.readdir(sourceCategoryDir, { withFileTypes: true });
|
|
36381
37008
|
for (const entry of entries) {
|
|
36382
37009
|
if (entry.name === ".DS_Store")
|
|
36383
37010
|
continue;
|
|
36384
|
-
const src =
|
|
36385
|
-
const dst =
|
|
36386
|
-
const claudeTop =
|
|
36387
|
-
const claudeStat = await
|
|
37011
|
+
const src = path19.join(sourceCategoryDir, entry.name);
|
|
37012
|
+
const dst = path19.join(agentsCategoryDir, entry.name);
|
|
37013
|
+
const claudeTop = path19.join(claudeDir, category, entry.name);
|
|
37014
|
+
const claudeStat = await import_fs_extra15.default.lstat(claudeTop).catch(() => null);
|
|
36388
37015
|
if (claudeStat && !claudeStat.isSymbolicLink()) {
|
|
36389
37016
|
onProgress?.(`${category}/${entry.name} (skipped - real dir in claude)`, "file");
|
|
36390
37017
|
continue;
|
|
36391
37018
|
}
|
|
36392
|
-
await
|
|
37019
|
+
await import_fs_extra15.default.copy(src, dst, { overwrite: true });
|
|
36393
37020
|
await applyPathPlaceholders(dst, claudeDir);
|
|
36394
37021
|
onProgress?.(`${category}/${entry.name}`, entry.isDirectory() ? "directory" : "file");
|
|
36395
37022
|
}
|
|
@@ -36408,8 +37035,8 @@ async function downloadFromPrivateGitHub(repo, branch, relativePath, targetPath,
|
|
|
36408
37035
|
return false;
|
|
36409
37036
|
}
|
|
36410
37037
|
const content = await response.arrayBuffer();
|
|
36411
|
-
await
|
|
36412
|
-
await
|
|
37038
|
+
await import_fs_extra15.default.ensureDir(path19.dirname(targetPath));
|
|
37039
|
+
await import_fs_extra15.default.writeFile(targetPath, Buffer.from(content));
|
|
36413
37040
|
return true;
|
|
36414
37041
|
} catch (error) {
|
|
36415
37042
|
console.error(`Error downloading ${relativePath}:`, error);
|
|
@@ -36434,10 +37061,10 @@ async function downloadDirectoryFromPrivateGitHub(repo, branch, dirPath, targetD
|
|
|
36434
37061
|
console.error(`Unexpected response for directory ${dirPath}`);
|
|
36435
37062
|
return false;
|
|
36436
37063
|
}
|
|
36437
|
-
await
|
|
37064
|
+
await import_fs_extra15.default.ensureDir(targetDir);
|
|
36438
37065
|
for (const file of files) {
|
|
36439
37066
|
const relativePath = dirPath ? `${dirPath}/${file.name}` : file.name;
|
|
36440
|
-
const targetPath =
|
|
37067
|
+
const targetPath = path19.join(targetDir, file.name);
|
|
36441
37068
|
const displayPath = relativePath.replace(/^(agents-config|ai-coding|claude-code-config|ai-config)\//, "");
|
|
36442
37069
|
if (file.type === "file") {
|
|
36443
37070
|
onProgress?.(displayPath, "file");
|
|
@@ -36460,8 +37087,8 @@ async function installProConfigs(options) {
|
|
|
36460
37087
|
codexFolder,
|
|
36461
37088
|
agentsFolder
|
|
36462
37089
|
});
|
|
36463
|
-
await
|
|
36464
|
-
await
|
|
37090
|
+
await import_fs_extra15.default.ensureDir(claudeDir);
|
|
37091
|
+
await import_fs_extra15.default.ensureDir(agentsDir);
|
|
36465
37092
|
const dest = { claudeDir, codexDir, agentsDir };
|
|
36466
37093
|
try {
|
|
36467
37094
|
const cacheConfigDir = await cloneOrUpdateRepo(githubToken);
|
|
@@ -36471,7 +37098,7 @@ async function installProConfigs(options) {
|
|
|
36471
37098
|
} catch (error) {
|
|
36472
37099
|
console.warn("Git caching failed, falling back to API download");
|
|
36473
37100
|
}
|
|
36474
|
-
const tempDir =
|
|
37101
|
+
const tempDir = path19.join(os16.tmpdir(), `aiblueprint-premium-${Date.now()}`);
|
|
36475
37102
|
try {
|
|
36476
37103
|
let success = false;
|
|
36477
37104
|
for (const candidate of CONFIG_FOLDER_CANDIDATES2) {
|
|
@@ -36485,8 +37112,8 @@ async function installProConfigs(options) {
|
|
|
36485
37112
|
await copyConfigFromCache(tempDir, dest, onProgress);
|
|
36486
37113
|
await replacePathPlaceholdersInDir(claudeDir, claudeDir);
|
|
36487
37114
|
for (const category of AGENT_CATEGORIES) {
|
|
36488
|
-
const agentsCategoryDir =
|
|
36489
|
-
if (await
|
|
37115
|
+
const agentsCategoryDir = path19.join(agentsDir, category);
|
|
37116
|
+
if (await import_fs_extra15.default.pathExists(agentsCategoryDir)) {
|
|
36490
37117
|
await replacePathPlaceholdersInDir(agentsCategoryDir, claudeDir);
|
|
36491
37118
|
}
|
|
36492
37119
|
}
|
|
@@ -36495,7 +37122,7 @@ async function installProConfigs(options) {
|
|
|
36495
37122
|
throw new Error(`Failed to install premium configs: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
36496
37123
|
} finally {
|
|
36497
37124
|
try {
|
|
36498
|
-
await
|
|
37125
|
+
await import_fs_extra15.default.remove(tempDir);
|
|
36499
37126
|
} catch {}
|
|
36500
37127
|
}
|
|
36501
37128
|
}
|
|
@@ -36506,27 +37133,27 @@ async function syncAllAgentSymlinks(agentsDir, claudeDir) {
|
|
|
36506
37133
|
}
|
|
36507
37134
|
|
|
36508
37135
|
// src/lib/token-storage.ts
|
|
36509
|
-
var
|
|
36510
|
-
import
|
|
36511
|
-
import
|
|
37136
|
+
var import_fs_extra16 = __toESM(require_lib4(), 1);
|
|
37137
|
+
import os17 from "os";
|
|
37138
|
+
import path20 from "path";
|
|
36512
37139
|
function getConfigDir() {
|
|
36513
|
-
const platform =
|
|
37140
|
+
const platform = os17.platform();
|
|
36514
37141
|
if (platform === "win32") {
|
|
36515
|
-
const appData = process.env.APPDATA ||
|
|
36516
|
-
return
|
|
37142
|
+
const appData = process.env.APPDATA || path20.join(os17.homedir(), "AppData", "Roaming");
|
|
37143
|
+
return path20.join(appData, "aiblueprint");
|
|
36517
37144
|
} else {
|
|
36518
|
-
const configHome = process.env.XDG_CONFIG_HOME ||
|
|
36519
|
-
return
|
|
37145
|
+
const configHome = process.env.XDG_CONFIG_HOME || path20.join(os17.homedir(), ".config");
|
|
37146
|
+
return path20.join(configHome, "aiblueprint");
|
|
36520
37147
|
}
|
|
36521
37148
|
}
|
|
36522
37149
|
function getTokenFilePath2() {
|
|
36523
|
-
return
|
|
37150
|
+
return path20.join(getConfigDir(), "token.txt");
|
|
36524
37151
|
}
|
|
36525
37152
|
async function saveToken(githubToken) {
|
|
36526
37153
|
const tokenFile = getTokenFilePath2();
|
|
36527
|
-
const configDir =
|
|
37154
|
+
const configDir = path20.dirname(tokenFile);
|
|
36528
37155
|
try {
|
|
36529
|
-
await
|
|
37156
|
+
await import_fs_extra16.default.ensureDir(configDir);
|
|
36530
37157
|
} catch (error) {
|
|
36531
37158
|
if (error.code === "EACCES") {
|
|
36532
37159
|
throw new Error(`Permission denied creating config directory: ${configDir}
|
|
@@ -36534,15 +37161,15 @@ async function saveToken(githubToken) {
|
|
|
36534
37161
|
}
|
|
36535
37162
|
throw error;
|
|
36536
37163
|
}
|
|
36537
|
-
await
|
|
37164
|
+
await import_fs_extra16.default.writeFile(tokenFile, githubToken, { mode: 384 });
|
|
36538
37165
|
}
|
|
36539
37166
|
async function getToken() {
|
|
36540
37167
|
const tokenFile = getTokenFilePath2();
|
|
36541
|
-
if (!await
|
|
37168
|
+
if (!await import_fs_extra16.default.pathExists(tokenFile)) {
|
|
36542
37169
|
return null;
|
|
36543
37170
|
}
|
|
36544
37171
|
try {
|
|
36545
|
-
const token = await
|
|
37172
|
+
const token = await import_fs_extra16.default.readFile(tokenFile, "utf-8");
|
|
36546
37173
|
return token.trim();
|
|
36547
37174
|
} catch (error) {
|
|
36548
37175
|
return null;
|
|
@@ -36551,12 +37178,12 @@ async function getToken() {
|
|
|
36551
37178
|
function getTokenInfo() {
|
|
36552
37179
|
return {
|
|
36553
37180
|
path: getTokenFilePath2(),
|
|
36554
|
-
platform:
|
|
37181
|
+
platform: os17.platform()
|
|
36555
37182
|
};
|
|
36556
37183
|
}
|
|
36557
37184
|
|
|
36558
37185
|
// src/commands/pro.ts
|
|
36559
|
-
var
|
|
37186
|
+
var import_fs_extra17 = __toESM(require_lib4(), 1);
|
|
36560
37187
|
var API_URL = "https://codeline.app/api/products";
|
|
36561
37188
|
var PRODUCT_IDS = ["prd_XJVgxVPbGG", "prd_NKabAkdOkw"];
|
|
36562
37189
|
async function countInstalledItems(claudeDir) {
|
|
@@ -36565,20 +37192,20 @@ async function countInstalledItems(claudeDir) {
|
|
|
36565
37192
|
skills: 0
|
|
36566
37193
|
};
|
|
36567
37194
|
try {
|
|
36568
|
-
const agentsDir =
|
|
36569
|
-
if (await
|
|
36570
|
-
const files = await
|
|
37195
|
+
const agentsDir = path21.join(claudeDir, "agents");
|
|
37196
|
+
if (await import_fs_extra17.default.pathExists(agentsDir)) {
|
|
37197
|
+
const files = await import_fs_extra17.default.readdir(agentsDir);
|
|
36571
37198
|
counts.agents = files.filter((f) => f.endsWith(".md")).length;
|
|
36572
37199
|
}
|
|
36573
37200
|
} catch (error) {
|
|
36574
37201
|
console.error("Failed to count agents:", error instanceof Error ? error.message : error);
|
|
36575
37202
|
}
|
|
36576
37203
|
try {
|
|
36577
|
-
const skillsDir =
|
|
36578
|
-
if (await
|
|
36579
|
-
const items = await
|
|
37204
|
+
const skillsDir = path21.join(claudeDir, "skills");
|
|
37205
|
+
if (await import_fs_extra17.default.pathExists(skillsDir)) {
|
|
37206
|
+
const items = await import_fs_extra17.default.readdir(skillsDir);
|
|
36580
37207
|
const dirs = await Promise.all(items.map(async (item) => {
|
|
36581
|
-
const stat = await
|
|
37208
|
+
const stat = await import_fs_extra17.default.stat(path21.join(skillsDir, item));
|
|
36582
37209
|
return stat.isDirectory();
|
|
36583
37210
|
}));
|
|
36584
37211
|
counts.skills = dirs.filter(Boolean).length;
|
|
@@ -36786,9 +37413,9 @@ async function proUpdateCommand(options = {}) {
|
|
|
36786
37413
|
}
|
|
36787
37414
|
|
|
36788
37415
|
// src/lib/sync-utils.ts
|
|
36789
|
-
var
|
|
36790
|
-
import
|
|
36791
|
-
import
|
|
37416
|
+
var import_fs_extra18 = __toESM(require_lib4(), 1);
|
|
37417
|
+
import path22 from "path";
|
|
37418
|
+
import crypto3 from "crypto";
|
|
36792
37419
|
var PREMIUM_REPO2 = "Melvynx/aiblueprint-cli-premium";
|
|
36793
37420
|
var PREMIUM_BRANCH2 = "main";
|
|
36794
37421
|
var CONFIG_FOLDER_CANDIDATES3 = ["agents-config", "ai-coding", "claude-code-config", "ai-config"];
|
|
@@ -36796,7 +37423,7 @@ function computeFileSha(content) {
|
|
|
36796
37423
|
const size = content.length;
|
|
36797
37424
|
const header = `blob ${size}\x00`;
|
|
36798
37425
|
const fullContent = Buffer.concat([Buffer.from(header), content]);
|
|
36799
|
-
return
|
|
37426
|
+
return crypto3.createHash("sha1").update(fullContent).digest("hex");
|
|
36800
37427
|
}
|
|
36801
37428
|
var resolvedConfigFolder = null;
|
|
36802
37429
|
async function resolveRemoteConfigFolder(githubToken) {
|
|
@@ -36858,7 +37485,7 @@ async function listRemoteFilesRecursive(dirPath, githubToken, basePath = "") {
|
|
|
36858
37485
|
}
|
|
36859
37486
|
async function computeLocalFileSha(filePath) {
|
|
36860
37487
|
try {
|
|
36861
|
-
const content = await
|
|
37488
|
+
const content = await import_fs_extra18.default.readFile(filePath);
|
|
36862
37489
|
return computeFileSha(content);
|
|
36863
37490
|
} catch {
|
|
36864
37491
|
return null;
|
|
@@ -36866,15 +37493,15 @@ async function computeLocalFileSha(filePath) {
|
|
|
36866
37493
|
}
|
|
36867
37494
|
async function listLocalFiles(dir) {
|
|
36868
37495
|
const files = [];
|
|
36869
|
-
if (!await
|
|
37496
|
+
if (!await import_fs_extra18.default.pathExists(dir)) {
|
|
36870
37497
|
return files;
|
|
36871
37498
|
}
|
|
36872
|
-
const items = await
|
|
37499
|
+
const items = await import_fs_extra18.default.readdir(dir);
|
|
36873
37500
|
for (const item of items) {
|
|
36874
37501
|
if (item === "node_modules" || item === ".DS_Store")
|
|
36875
37502
|
continue;
|
|
36876
|
-
const fullPath =
|
|
36877
|
-
const stat = await
|
|
37503
|
+
const fullPath = path22.join(dir, item);
|
|
37504
|
+
const stat = await import_fs_extra18.default.stat(fullPath).catch(() => null);
|
|
36878
37505
|
if (!stat)
|
|
36879
37506
|
continue;
|
|
36880
37507
|
if (stat.isDirectory()) {
|
|
@@ -36889,13 +37516,13 @@ async function listLocalFiles(dir) {
|
|
|
36889
37516
|
}
|
|
36890
37517
|
async function listLocalFilesRecursive(dir, basePath) {
|
|
36891
37518
|
const files = [];
|
|
36892
|
-
const items = await
|
|
37519
|
+
const items = await import_fs_extra18.default.readdir(dir).catch(() => []);
|
|
36893
37520
|
for (const item of items) {
|
|
36894
37521
|
if (item === "node_modules" || item === ".DS_Store")
|
|
36895
37522
|
continue;
|
|
36896
|
-
const fullPath =
|
|
37523
|
+
const fullPath = path22.join(dir, item);
|
|
36897
37524
|
const relativePath = `${basePath}/${item}`;
|
|
36898
|
-
const stat = await
|
|
37525
|
+
const stat = await import_fs_extra18.default.stat(fullPath).catch(() => null);
|
|
36899
37526
|
if (!stat)
|
|
36900
37527
|
continue;
|
|
36901
37528
|
if (stat.isDirectory()) {
|
|
@@ -36909,14 +37536,14 @@ async function listLocalFilesRecursive(dir, basePath) {
|
|
|
36909
37536
|
return files;
|
|
36910
37537
|
}
|
|
36911
37538
|
async function listClaudeRealTopLevel(claudeCategoryDir) {
|
|
36912
|
-
if (!await
|
|
37539
|
+
if (!await import_fs_extra18.default.pathExists(claudeCategoryDir))
|
|
36913
37540
|
return [];
|
|
36914
|
-
const entries = await
|
|
37541
|
+
const entries = await import_fs_extra18.default.readdir(claudeCategoryDir).catch(() => []);
|
|
36915
37542
|
const real = [];
|
|
36916
37543
|
for (const name of entries) {
|
|
36917
37544
|
if (name === "node_modules" || name === ".DS_Store")
|
|
36918
37545
|
continue;
|
|
36919
|
-
const stat = await
|
|
37546
|
+
const stat = await import_fs_extra18.default.lstat(path22.join(claudeCategoryDir, name)).catch(() => null);
|
|
36920
37547
|
if (!stat)
|
|
36921
37548
|
continue;
|
|
36922
37549
|
if (stat.isDirectory())
|
|
@@ -36933,7 +37560,7 @@ async function analyzeCategory(category, claudeDir, agentsDir, githubToken) {
|
|
|
36933
37560
|
const items = [];
|
|
36934
37561
|
const useAgents = isAgentCategory(category);
|
|
36935
37562
|
const localBase = useAgents ? agentsDir : claudeDir;
|
|
36936
|
-
const localDir =
|
|
37563
|
+
const localDir = path22.join(localBase, category);
|
|
36937
37564
|
const remoteCategoryPath = getRemoteCategoryPath(category);
|
|
36938
37565
|
const remoteFiles = await listRemoteFilesRecursive(remoteCategoryPath, githubToken);
|
|
36939
37566
|
const localFiles = await listLocalFiles(localDir);
|
|
@@ -36947,7 +37574,7 @@ async function analyzeCategory(category, claudeDir, agentsDir, githubToken) {
|
|
|
36947
37574
|
}
|
|
36948
37575
|
const localSet = new Set(localFiles);
|
|
36949
37576
|
for (const [remotePath, { sha, isFolder }] of remoteSet) {
|
|
36950
|
-
const localPath =
|
|
37577
|
+
const localPath = path22.join(localDir, remotePath);
|
|
36951
37578
|
if (isFolder) {
|
|
36952
37579
|
continue;
|
|
36953
37580
|
}
|
|
@@ -36982,7 +37609,7 @@ async function analyzeCategory(category, claudeDir, agentsDir, githubToken) {
|
|
|
36982
37609
|
for (const localPath of localSet) {
|
|
36983
37610
|
agentsTopLevels.add(localPath.split("/")[0]);
|
|
36984
37611
|
}
|
|
36985
|
-
const claudeCategoryDir =
|
|
37612
|
+
const claudeCategoryDir = path22.join(claudeDir, category);
|
|
36986
37613
|
const claudeRealEntries = await listClaudeRealTopLevel(claudeCategoryDir);
|
|
36987
37614
|
for (const top of claudeRealEntries) {
|
|
36988
37615
|
if (!remoteTopLevels.has(top))
|
|
@@ -37041,13 +37668,13 @@ async function downloadFromPrivateGitHub2(relativePath, targetPath, githubToken,
|
|
|
37041
37668
|
return false;
|
|
37042
37669
|
}
|
|
37043
37670
|
const content = await response.arrayBuffer();
|
|
37044
|
-
await
|
|
37671
|
+
await import_fs_extra18.default.ensureDir(path22.dirname(targetPath));
|
|
37045
37672
|
if (isTextFile(relativePath)) {
|
|
37046
37673
|
const textContent = Buffer.from(content).toString("utf-8");
|
|
37047
37674
|
const transformedContent = transformFileContent(textContent, claudeDir);
|
|
37048
|
-
await
|
|
37675
|
+
await import_fs_extra18.default.writeFile(targetPath, transformedContent, "utf-8");
|
|
37049
37676
|
} else {
|
|
37050
|
-
await
|
|
37677
|
+
await import_fs_extra18.default.writeFile(targetPath, Buffer.from(content));
|
|
37051
37678
|
}
|
|
37052
37679
|
return true;
|
|
37053
37680
|
} catch {
|
|
@@ -37063,27 +37690,27 @@ async function syncSelectedItems(claudeDir, items, githubToken, agentsDir, onPro
|
|
|
37063
37690
|
for (const item of items) {
|
|
37064
37691
|
const useAgents = isAgentCategory(item.category);
|
|
37065
37692
|
const baseDir = useAgents ? agentsDir : claudeDir;
|
|
37066
|
-
const targetPath =
|
|
37693
|
+
const targetPath = path22.join(baseDir, item.relativePath);
|
|
37067
37694
|
if (item.status === "migration" && useAgents) {
|
|
37068
37695
|
const topName = item.name.split("/")[0];
|
|
37069
|
-
const agentsTop =
|
|
37070
|
-
const claudeTop =
|
|
37696
|
+
const agentsTop = path22.join(agentsDir, item.category, topName);
|
|
37697
|
+
const claudeTop = path22.join(claudeDir, item.category, topName);
|
|
37071
37698
|
try {
|
|
37072
|
-
const claudeStat = await
|
|
37699
|
+
const claudeStat = await import_fs_extra18.default.lstat(claudeTop).catch(() => null);
|
|
37073
37700
|
if (!claudeStat || claudeStat.isSymbolicLink()) {
|
|
37074
37701
|
onProgress?.(item.relativePath, "skipping (no real dir to migrate)");
|
|
37075
37702
|
failed++;
|
|
37076
37703
|
continue;
|
|
37077
37704
|
}
|
|
37078
|
-
const agentsExists = await
|
|
37705
|
+
const agentsExists = await import_fs_extra18.default.pathExists(agentsTop);
|
|
37079
37706
|
if (agentsExists) {
|
|
37080
37707
|
onProgress?.(item.relativePath, "skipping (already in .agents)");
|
|
37081
37708
|
failed++;
|
|
37082
37709
|
continue;
|
|
37083
37710
|
}
|
|
37084
37711
|
onProgress?.(item.relativePath, "moving to .agents");
|
|
37085
|
-
await
|
|
37086
|
-
await
|
|
37712
|
+
await import_fs_extra18.default.ensureDir(path22.dirname(agentsTop));
|
|
37713
|
+
await import_fs_extra18.default.move(claudeTop, agentsTop);
|
|
37087
37714
|
migrated++;
|
|
37088
37715
|
touchedAgentCategories.add(item.category);
|
|
37089
37716
|
} catch {
|
|
@@ -37093,8 +37720,8 @@ async function syncSelectedItems(claudeDir, items, githubToken, agentsDir, onPro
|
|
|
37093
37720
|
}
|
|
37094
37721
|
if (useAgents) {
|
|
37095
37722
|
const topName = item.name.split("/")[0];
|
|
37096
|
-
const claudeTop =
|
|
37097
|
-
const claudeTopStat = await
|
|
37723
|
+
const claudeTop = path22.join(claudeDir, item.category, topName);
|
|
37724
|
+
const claudeTopStat = await import_fs_extra18.default.lstat(claudeTop).catch(() => null);
|
|
37098
37725
|
if (claudeTopStat && !claudeTopStat.isSymbolicLink()) {
|
|
37099
37726
|
onProgress?.(item.relativePath, "skipping (real dir in .claude)");
|
|
37100
37727
|
failed++;
|
|
@@ -37104,7 +37731,7 @@ async function syncSelectedItems(claudeDir, items, githubToken, agentsDir, onPro
|
|
|
37104
37731
|
if (item.status === "deleted") {
|
|
37105
37732
|
onProgress?.(item.relativePath, "deleting");
|
|
37106
37733
|
try {
|
|
37107
|
-
await
|
|
37734
|
+
await import_fs_extra18.default.remove(targetPath);
|
|
37108
37735
|
deleted++;
|
|
37109
37736
|
if (useAgents)
|
|
37110
37737
|
touchedAgentCategories.add(item.category);
|
|
@@ -37441,106 +38068,6 @@ async function proSyncCommand(options = {}) {
|
|
|
37441
38068
|
}
|
|
37442
38069
|
}
|
|
37443
38070
|
|
|
37444
|
-
// src/lib/backup-utils.ts
|
|
37445
|
-
var import_fs_extra17 = __toESM(require_lib4(), 1);
|
|
37446
|
-
import path21 from "path";
|
|
37447
|
-
import os16 from "os";
|
|
37448
|
-
var BACKUP_BASE_DIR = path21.join(os16.homedir(), ".config", "aiblueprint", "backup");
|
|
37449
|
-
function formatDate(date) {
|
|
37450
|
-
const pad = (n) => n.toString().padStart(2, "0");
|
|
37451
|
-
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}-${pad(date.getHours())}-${pad(date.getMinutes())}-${pad(date.getSeconds())}`;
|
|
37452
|
-
}
|
|
37453
|
-
async function listBackups() {
|
|
37454
|
-
const exists = await import_fs_extra17.default.pathExists(BACKUP_BASE_DIR);
|
|
37455
|
-
if (!exists) {
|
|
37456
|
-
return [];
|
|
37457
|
-
}
|
|
37458
|
-
const entries = await import_fs_extra17.default.readdir(BACKUP_BASE_DIR, { withFileTypes: true });
|
|
37459
|
-
const backups = [];
|
|
37460
|
-
for (const entry of entries) {
|
|
37461
|
-
if (!entry.isDirectory())
|
|
37462
|
-
continue;
|
|
37463
|
-
const match = entry.name.match(/^(\d{4})-(\d{2})-(\d{2})-(\d{2})-(\d{2})-(\d{2})$/);
|
|
37464
|
-
if (!match)
|
|
37465
|
-
continue;
|
|
37466
|
-
const [, year, month, day, hour, minute, second] = match;
|
|
37467
|
-
const date = new Date(parseInt(year), parseInt(month) - 1, parseInt(day), parseInt(hour), parseInt(minute), parseInt(second));
|
|
37468
|
-
backups.push({
|
|
37469
|
-
name: entry.name,
|
|
37470
|
-
path: path21.join(BACKUP_BASE_DIR, entry.name),
|
|
37471
|
-
date
|
|
37472
|
-
});
|
|
37473
|
-
}
|
|
37474
|
-
return backups.sort((a, b3) => b3.date.getTime() - a.date.getTime());
|
|
37475
|
-
}
|
|
37476
|
-
var AGENTS_BACKUP_SUBDIR = ".agents";
|
|
37477
|
-
var CLAUDE_ITEMS = ["commands", "agents", "skills", "scripts", "settings.json"];
|
|
37478
|
-
async function copyForBackup(sourcePath, destPath) {
|
|
37479
|
-
await import_fs_extra17.default.copy(sourcePath, destPath, {
|
|
37480
|
-
overwrite: true,
|
|
37481
|
-
dereference: false,
|
|
37482
|
-
filter: async (src) => {
|
|
37483
|
-
try {
|
|
37484
|
-
const stat = await import_fs_extra17.default.lstat(src);
|
|
37485
|
-
return !stat.isSymbolicLink();
|
|
37486
|
-
} catch {
|
|
37487
|
-
return true;
|
|
37488
|
-
}
|
|
37489
|
-
}
|
|
37490
|
-
});
|
|
37491
|
-
}
|
|
37492
|
-
async function hasMeaningfulContent(dir) {
|
|
37493
|
-
if (!await import_fs_extra17.default.pathExists(dir))
|
|
37494
|
-
return false;
|
|
37495
|
-
const files = await import_fs_extra17.default.readdir(dir);
|
|
37496
|
-
return files.some((f) => f !== ".DS_Store");
|
|
37497
|
-
}
|
|
37498
|
-
async function loadBackup(backupPath, claudeDir, agentsDir) {
|
|
37499
|
-
const exists = await import_fs_extra17.default.pathExists(backupPath);
|
|
37500
|
-
if (!exists) {
|
|
37501
|
-
throw new Error(`Backup not found: ${backupPath}`);
|
|
37502
|
-
}
|
|
37503
|
-
await import_fs_extra17.default.ensureDir(claudeDir);
|
|
37504
|
-
for (const item of CLAUDE_ITEMS) {
|
|
37505
|
-
const sourcePath = path21.join(backupPath, item);
|
|
37506
|
-
const destPath = path21.join(claudeDir, item);
|
|
37507
|
-
if (await import_fs_extra17.default.pathExists(sourcePath)) {
|
|
37508
|
-
await copyForBackup(sourcePath, destPath);
|
|
37509
|
-
}
|
|
37510
|
-
}
|
|
37511
|
-
if (agentsDir) {
|
|
37512
|
-
const agentsBackupPath = path21.join(backupPath, AGENTS_BACKUP_SUBDIR);
|
|
37513
|
-
if (await import_fs_extra17.default.pathExists(agentsBackupPath)) {
|
|
37514
|
-
await import_fs_extra17.default.ensureDir(agentsDir);
|
|
37515
|
-
await copyForBackup(agentsBackupPath, agentsDir);
|
|
37516
|
-
}
|
|
37517
|
-
}
|
|
37518
|
-
}
|
|
37519
|
-
async function createBackup(claudeDir, agentsDir) {
|
|
37520
|
-
const claudeHasContent = await hasMeaningfulContent(claudeDir);
|
|
37521
|
-
const agentsHasContent = agentsDir ? await hasMeaningfulContent(agentsDir) : false;
|
|
37522
|
-
if (!claudeHasContent && !agentsHasContent) {
|
|
37523
|
-
return null;
|
|
37524
|
-
}
|
|
37525
|
-
const timestamp3 = formatDate(new Date);
|
|
37526
|
-
const backupPath = path21.join(BACKUP_BASE_DIR, timestamp3);
|
|
37527
|
-
await import_fs_extra17.default.ensureDir(backupPath);
|
|
37528
|
-
if (claudeHasContent) {
|
|
37529
|
-
for (const item of CLAUDE_ITEMS) {
|
|
37530
|
-
const sourcePath = path21.join(claudeDir, item);
|
|
37531
|
-
const destPath = path21.join(backupPath, item);
|
|
37532
|
-
if (await import_fs_extra17.default.pathExists(sourcePath)) {
|
|
37533
|
-
await copyForBackup(sourcePath, destPath);
|
|
37534
|
-
}
|
|
37535
|
-
}
|
|
37536
|
-
}
|
|
37537
|
-
if (agentsHasContent && agentsDir) {
|
|
37538
|
-
const destPath = path21.join(backupPath, AGENTS_BACKUP_SUBDIR);
|
|
37539
|
-
await copyForBackup(agentsDir, destPath);
|
|
37540
|
-
}
|
|
37541
|
-
return backupPath;
|
|
37542
|
-
}
|
|
37543
|
-
|
|
37544
38071
|
// src/commands/backup.ts
|
|
37545
38072
|
function formatBackupDate(date) {
|
|
37546
38073
|
const now = new Date;
|
|
@@ -37561,7 +38088,7 @@ function formatBackupDate(date) {
|
|
|
37561
38088
|
return `${date.toLocaleString()} (${relative})`;
|
|
37562
38089
|
}
|
|
37563
38090
|
async function backupLoadCommand(options = {}) {
|
|
37564
|
-
const { claudeDir, agentsDir } = resolveFolders(options);
|
|
38091
|
+
const { claudeDir, codexDir, agentsDir } = resolveFolders(options);
|
|
37565
38092
|
Ie(source_default.blue("\uD83D\uDCE6 Load Backup"));
|
|
37566
38093
|
const spinner = Y2();
|
|
37567
38094
|
spinner.start("Scanning for backups...");
|
|
@@ -37597,7 +38124,7 @@ async function backupLoadCommand(options = {}) {
|
|
|
37597
38124
|
process.exit(0);
|
|
37598
38125
|
}
|
|
37599
38126
|
spinner.start("Creating backup of current configuration...");
|
|
37600
|
-
const currentBackup = await createBackup(claudeDir, agentsDir);
|
|
38127
|
+
const currentBackup = await createBackup(claudeDir, codexDir, agentsDir);
|
|
37601
38128
|
if (currentBackup) {
|
|
37602
38129
|
spinner.stop(`Current config backed up to: ${source_default.gray(currentBackup)}`);
|
|
37603
38130
|
} else {
|
|
@@ -37605,7 +38132,7 @@ async function backupLoadCommand(options = {}) {
|
|
|
37605
38132
|
}
|
|
37606
38133
|
spinner.start("Restoring backup...");
|
|
37607
38134
|
try {
|
|
37608
|
-
await loadBackup(selected.path, claudeDir, agentsDir);
|
|
38135
|
+
await loadBackup(selected.path, claudeDir, codexDir, agentsDir);
|
|
37609
38136
|
spinner.stop("Backup restored successfully");
|
|
37610
38137
|
M2.success(`Restored configuration from ${source_default.cyan(selected.name)}`);
|
|
37611
38138
|
Se(source_default.green("✅ Backup loaded successfully"));
|
|
@@ -37642,7 +38169,7 @@ function printSnapshots(title, snapshots) {
|
|
|
37642
38169
|
}
|
|
37643
38170
|
async function configsSaveCommand(name, options = {}) {
|
|
37644
38171
|
try {
|
|
37645
|
-
console.log(source_default.gray("Saving .claude, .codex, and .agents
|
|
38172
|
+
console.log(source_default.gray("Saving full .claude, .codex, and .agents folders..."));
|
|
37646
38173
|
const snapshotPath = await saveNamedConfig(name, options);
|
|
37647
38174
|
console.log(source_default.green(`Saved config "${name}"`));
|
|
37648
38175
|
console.log(source_default.gray(snapshotPath));
|
|
@@ -37718,19 +38245,19 @@ async function configsBackupsCreateCommand(reason, options = {}) {
|
|
|
37718
38245
|
}
|
|
37719
38246
|
|
|
37720
38247
|
// src/commands/openclaw-pro.ts
|
|
37721
|
-
import
|
|
37722
|
-
import
|
|
38248
|
+
import os20 from "os";
|
|
38249
|
+
import path25 from "path";
|
|
37723
38250
|
|
|
37724
38251
|
// src/lib/openclaw-installer.ts
|
|
37725
|
-
var
|
|
37726
|
-
import
|
|
37727
|
-
import
|
|
38252
|
+
var import_fs_extra19 = __toESM(require_lib4(), 1);
|
|
38253
|
+
import os18 from "os";
|
|
38254
|
+
import path23 from "path";
|
|
37728
38255
|
import { exec as exec4 } from "child_process";
|
|
37729
38256
|
import { promisify as promisify3 } from "util";
|
|
37730
38257
|
var execAsync3 = promisify3(exec4);
|
|
37731
38258
|
var OPENCLAW_PRO_REPO = "Melvynx/openclawpro";
|
|
37732
38259
|
function getCacheRepoDir2() {
|
|
37733
|
-
return
|
|
38260
|
+
return path23.join(os18.homedir(), ".config", "openclaw", "pro-repos", "openclawpro");
|
|
37734
38261
|
}
|
|
37735
38262
|
async function execGitWithAuth2(command, token, repoUrl, cwd) {
|
|
37736
38263
|
const authenticatedUrl = `https://x-access-token:${token}@${repoUrl.replace(/^https?:\/\//, "")}`;
|
|
@@ -37744,33 +38271,33 @@ async function execGitWithAuth2(command, token, repoUrl, cwd) {
|
|
|
37744
38271
|
async function cloneOrUpdateRepo2(token) {
|
|
37745
38272
|
const cacheDir = getCacheRepoDir2();
|
|
37746
38273
|
const repoUrl = `https://github.com/${OPENCLAW_PRO_REPO}.git`;
|
|
37747
|
-
if (await
|
|
38274
|
+
if (await import_fs_extra19.default.pathExists(path23.join(cacheDir, ".git"))) {
|
|
37748
38275
|
try {
|
|
37749
38276
|
await execGitWithAuth2("pull", token, repoUrl, cacheDir);
|
|
37750
38277
|
} catch (error) {
|
|
37751
|
-
await
|
|
37752
|
-
await
|
|
38278
|
+
await import_fs_extra19.default.remove(cacheDir);
|
|
38279
|
+
await import_fs_extra19.default.ensureDir(path23.dirname(cacheDir));
|
|
37753
38280
|
await execGitWithAuth2(`clone ${repoUrl} ${cacheDir}`, token, repoUrl);
|
|
37754
38281
|
}
|
|
37755
38282
|
} else {
|
|
37756
|
-
await
|
|
38283
|
+
await import_fs_extra19.default.ensureDir(path23.dirname(cacheDir));
|
|
37757
38284
|
await execGitWithAuth2(`clone ${repoUrl} ${cacheDir}`, token, repoUrl);
|
|
37758
38285
|
}
|
|
37759
|
-
return
|
|
38286
|
+
return path23.join(cacheDir, "openclaw-config");
|
|
37760
38287
|
}
|
|
37761
38288
|
async function copyConfigFromCache2(cacheConfigDir, targetDir, onProgress) {
|
|
37762
38289
|
const walk = async (dir, baseDir = dir) => {
|
|
37763
|
-
const entries = await
|
|
38290
|
+
const entries = await import_fs_extra19.default.readdir(dir, { withFileTypes: true });
|
|
37764
38291
|
for (const entry of entries) {
|
|
37765
|
-
const sourcePath =
|
|
37766
|
-
const relativePath =
|
|
37767
|
-
const targetPath =
|
|
38292
|
+
const sourcePath = path23.join(dir, entry.name);
|
|
38293
|
+
const relativePath = path23.relative(baseDir, sourcePath);
|
|
38294
|
+
const targetPath = path23.join(targetDir, relativePath);
|
|
37768
38295
|
if (entry.isDirectory()) {
|
|
37769
|
-
await
|
|
38296
|
+
await import_fs_extra19.default.ensureDir(targetPath);
|
|
37770
38297
|
onProgress?.(relativePath, "directory");
|
|
37771
38298
|
await walk(sourcePath, baseDir);
|
|
37772
38299
|
} else {
|
|
37773
|
-
await
|
|
38300
|
+
await import_fs_extra19.default.copy(sourcePath, targetPath, { overwrite: true });
|
|
37774
38301
|
onProgress?.(relativePath, "file");
|
|
37775
38302
|
}
|
|
37776
38303
|
}
|
|
@@ -37779,7 +38306,7 @@ async function copyConfigFromCache2(cacheConfigDir, targetDir, onProgress) {
|
|
|
37779
38306
|
}
|
|
37780
38307
|
async function installOpenclawProConfigs(options) {
|
|
37781
38308
|
const { githubToken, openclawFolder, onProgress } = options;
|
|
37782
|
-
const targetFolder = openclawFolder ||
|
|
38309
|
+
const targetFolder = openclawFolder || path23.join(os18.homedir(), ".openclaw");
|
|
37783
38310
|
try {
|
|
37784
38311
|
const cacheConfigDir = await cloneOrUpdateRepo2(githubToken);
|
|
37785
38312
|
await copyConfigFromCache2(cacheConfigDir, targetFolder, onProgress);
|
|
@@ -37790,28 +38317,28 @@ async function installOpenclawProConfigs(options) {
|
|
|
37790
38317
|
}
|
|
37791
38318
|
|
|
37792
38319
|
// src/lib/openclaw-token-storage.ts
|
|
37793
|
-
var
|
|
37794
|
-
import
|
|
37795
|
-
import
|
|
38320
|
+
var import_fs_extra20 = __toESM(require_lib4(), 1);
|
|
38321
|
+
import os19 from "os";
|
|
38322
|
+
import path24 from "path";
|
|
37796
38323
|
function getConfigDir2() {
|
|
37797
|
-
const platform =
|
|
38324
|
+
const platform = os19.platform();
|
|
37798
38325
|
if (platform === "win32") {
|
|
37799
|
-
return
|
|
38326
|
+
return path24.join(process.env.APPDATA || os19.homedir(), "openclaw");
|
|
37800
38327
|
}
|
|
37801
|
-
return
|
|
38328
|
+
return path24.join(os19.homedir(), ".config", "openclaw");
|
|
37802
38329
|
}
|
|
37803
38330
|
function getTokenPath() {
|
|
37804
|
-
return
|
|
38331
|
+
return path24.join(getConfigDir2(), "token.txt");
|
|
37805
38332
|
}
|
|
37806
38333
|
async function saveOpenclawToken(githubToken) {
|
|
37807
38334
|
const configDir = getConfigDir2();
|
|
37808
|
-
await
|
|
37809
|
-
await
|
|
38335
|
+
await import_fs_extra20.default.ensureDir(configDir);
|
|
38336
|
+
await import_fs_extra20.default.writeFile(getTokenPath(), githubToken, { mode: 384 });
|
|
37810
38337
|
}
|
|
37811
38338
|
async function getOpenclawToken() {
|
|
37812
38339
|
const tokenPath = getTokenPath();
|
|
37813
|
-
if (await
|
|
37814
|
-
const token = await
|
|
38340
|
+
if (await import_fs_extra20.default.pathExists(tokenPath)) {
|
|
38341
|
+
const token = await import_fs_extra20.default.readFile(tokenPath, "utf8");
|
|
37815
38342
|
return token.trim();
|
|
37816
38343
|
}
|
|
37817
38344
|
return null;
|
|
@@ -37819,12 +38346,12 @@ async function getOpenclawToken() {
|
|
|
37819
38346
|
function getOpenclawTokenInfo() {
|
|
37820
38347
|
return {
|
|
37821
38348
|
path: getTokenPath(),
|
|
37822
|
-
platform:
|
|
38349
|
+
platform: os19.platform()
|
|
37823
38350
|
};
|
|
37824
38351
|
}
|
|
37825
38352
|
|
|
37826
38353
|
// src/commands/openclaw-pro.ts
|
|
37827
|
-
var
|
|
38354
|
+
var import_fs_extra21 = __toESM(require_lib4(), 1);
|
|
37828
38355
|
var API_URL2 = "https://codeline.app/api/products";
|
|
37829
38356
|
var OPENCLAW_PRODUCT_ID = "prd_t2GRwX3aH1";
|
|
37830
38357
|
var CLAUDE_CODE_TOOLS_INSTRUCTIONS = `
|
|
@@ -37931,7 +38458,7 @@ async function openclawProSetupCommand(options = {}) {
|
|
|
37931
38458
|
Se(source_default.red("❌ Not activated"));
|
|
37932
38459
|
process.exit(1);
|
|
37933
38460
|
}
|
|
37934
|
-
const openclawDir = options.folder ?
|
|
38461
|
+
const openclawDir = options.folder ? path25.resolve(options.folder) : path25.join(os20.homedir(), ".openclaw");
|
|
37935
38462
|
const spinner = Y2();
|
|
37936
38463
|
const onProgress = (file, type) => {
|
|
37937
38464
|
spinner.message(`Installing: ${source_default.cyan(file)} ${source_default.gray(`(${type})`)}`);
|
|
@@ -37944,23 +38471,23 @@ async function openclawProSetupCommand(options = {}) {
|
|
|
37944
38471
|
});
|
|
37945
38472
|
spinner.stop("OpenClaw Pro configurations installed");
|
|
37946
38473
|
let skillCount = 0;
|
|
37947
|
-
const skillsDir =
|
|
37948
|
-
if (await
|
|
37949
|
-
const items = await
|
|
38474
|
+
const skillsDir = path25.join(openclawDir, "skills");
|
|
38475
|
+
if (await import_fs_extra21.default.pathExists(skillsDir)) {
|
|
38476
|
+
const items = await import_fs_extra21.default.readdir(skillsDir);
|
|
37950
38477
|
const dirs = await Promise.all(items.map(async (item) => {
|
|
37951
|
-
const stat = await
|
|
38478
|
+
const stat = await import_fs_extra21.default.stat(path25.join(skillsDir, item));
|
|
37952
38479
|
return stat.isDirectory();
|
|
37953
38480
|
}));
|
|
37954
38481
|
skillCount = dirs.filter(Boolean).length;
|
|
37955
38482
|
}
|
|
37956
38483
|
spinner.start("Setting up workspace TOOLS.md...");
|
|
37957
|
-
const workspaceDir =
|
|
37958
|
-
const toolsPath =
|
|
37959
|
-
await
|
|
37960
|
-
if (await
|
|
37961
|
-
const existingContent = await
|
|
38484
|
+
const workspaceDir = path25.join(openclawDir, "workspace");
|
|
38485
|
+
const toolsPath = path25.join(workspaceDir, "TOOLS.md");
|
|
38486
|
+
await import_fs_extra21.default.ensureDir(workspaceDir);
|
|
38487
|
+
if (await import_fs_extra21.default.pathExists(toolsPath)) {
|
|
38488
|
+
const existingContent = await import_fs_extra21.default.readFile(toolsPath, "utf-8");
|
|
37962
38489
|
if (!existingContent.includes("Claude Code CLI")) {
|
|
37963
|
-
await
|
|
38490
|
+
await import_fs_extra21.default.appendFile(toolsPath, `
|
|
37964
38491
|
|
|
37965
38492
|
` + CLAUDE_CODE_TOOLS_INSTRUCTIONS);
|
|
37966
38493
|
spinner.stop("TOOLS.md updated with Claude Code instructions");
|
|
@@ -37974,7 +38501,7 @@ Skills define _how_ tools work. This file is for _your_ specifics — the stuff
|
|
|
37974
38501
|
|
|
37975
38502
|
${CLAUDE_CODE_TOOLS_INSTRUCTIONS}
|
|
37976
38503
|
`;
|
|
37977
|
-
await
|
|
38504
|
+
await import_fs_extra21.default.writeFile(toolsPath, defaultToolsMd);
|
|
37978
38505
|
spinner.stop("TOOLS.md created with Claude Code instructions");
|
|
37979
38506
|
}
|
|
37980
38507
|
spinner.start("Creating claude-run wrapper...");
|
|
@@ -37985,9 +38512,9 @@ ${CLAUDE_CODE_TOOLS_INSTRUCTIONS}
|
|
|
37985
38512
|
script -q -c "claude $*" /dev/null
|
|
37986
38513
|
`;
|
|
37987
38514
|
const binDir = "/usr/local/bin";
|
|
37988
|
-
const wrapperPath =
|
|
38515
|
+
const wrapperPath = path25.join(binDir, "claude-run");
|
|
37989
38516
|
try {
|
|
37990
|
-
await
|
|
38517
|
+
await import_fs_extra21.default.writeFile(wrapperPath, claudeRunWrapper, { mode: 493 });
|
|
37991
38518
|
spinner.stop("claude-run wrapper created");
|
|
37992
38519
|
} catch {
|
|
37993
38520
|
spinner.stop("claude-run wrapper skipped (no write access to /usr/local/bin)");
|
|
@@ -38036,12 +38563,12 @@ async function openclawProUpdateCommand(options = {}) {
|
|
|
38036
38563
|
}
|
|
38037
38564
|
|
|
38038
38565
|
// src/commands/dynamic-scripts.ts
|
|
38039
|
-
import
|
|
38566
|
+
import path28 from "path";
|
|
38040
38567
|
import { homedir } from "os";
|
|
38041
38568
|
|
|
38042
38569
|
// src/lib/script-parser.ts
|
|
38043
|
-
var
|
|
38044
|
-
import
|
|
38570
|
+
var import_fs_extra22 = __toESM(require_lib4(), 1);
|
|
38571
|
+
import path26 from "path";
|
|
38045
38572
|
var EXCLUDED_SCRIPTS = ["test", "lint", "format", "start"];
|
|
38046
38573
|
var EXCLUDED_SUFFIXES = [":test", ":lint", ":test-fixtures", ":start"];
|
|
38047
38574
|
function shouldIncludeScript(scriptName) {
|
|
@@ -38052,12 +38579,12 @@ function shouldIncludeScript(scriptName) {
|
|
|
38052
38579
|
return true;
|
|
38053
38580
|
}
|
|
38054
38581
|
async function readScriptsPackageJson(claudeDir) {
|
|
38055
|
-
const packageJsonPath =
|
|
38582
|
+
const packageJsonPath = path26.join(claudeDir, "scripts", "package.json");
|
|
38056
38583
|
try {
|
|
38057
|
-
if (!await
|
|
38584
|
+
if (!await import_fs_extra22.default.pathExists(packageJsonPath)) {
|
|
38058
38585
|
return null;
|
|
38059
38586
|
}
|
|
38060
|
-
const content = await
|
|
38587
|
+
const content = await import_fs_extra22.default.readFile(packageJsonPath, "utf-8");
|
|
38061
38588
|
const parsed = JSON.parse(content);
|
|
38062
38589
|
return parsed.scripts || null;
|
|
38063
38590
|
} catch (error) {
|
|
@@ -38101,14 +38628,14 @@ function groupScriptsByPrefix(commands) {
|
|
|
38101
38628
|
}
|
|
38102
38629
|
|
|
38103
38630
|
// src/commands/script-runner.ts
|
|
38104
|
-
var
|
|
38631
|
+
var import_fs_extra23 = __toESM(require_lib4(), 1);
|
|
38105
38632
|
import { spawn as spawn2 } from "child_process";
|
|
38106
38633
|
import { execSync as execSync4 } from "child_process";
|
|
38107
|
-
import
|
|
38108
|
-
import
|
|
38634
|
+
import path27 from "path";
|
|
38635
|
+
import os21 from "os";
|
|
38109
38636
|
function checkCommand2(cmd) {
|
|
38110
38637
|
try {
|
|
38111
|
-
const isWindows2 =
|
|
38638
|
+
const isWindows2 = os21.platform() === "win32";
|
|
38112
38639
|
const whichCmd = isWindows2 ? `where ${cmd}` : `which ${cmd}`;
|
|
38113
38640
|
execSync4(whichCmd, { stdio: "ignore" });
|
|
38114
38641
|
return true;
|
|
@@ -38134,18 +38661,18 @@ async function executeScript(scriptName, claudeDir) {
|
|
|
38134
38661
|
console.error(source_default.red("Bun is not installed. Install with: npm install -g bun"));
|
|
38135
38662
|
return 1;
|
|
38136
38663
|
}
|
|
38137
|
-
const scriptsDir =
|
|
38138
|
-
if (!await
|
|
38664
|
+
const scriptsDir = path27.join(claudeDir, "scripts");
|
|
38665
|
+
if (!await import_fs_extra23.default.pathExists(scriptsDir)) {
|
|
38139
38666
|
console.error(source_default.red(`Scripts directory not found at ${scriptsDir}`));
|
|
38140
38667
|
console.log(source_default.gray("Run: aiblueprint agents setup"));
|
|
38141
38668
|
return 1;
|
|
38142
38669
|
}
|
|
38143
|
-
const packageJsonPath =
|
|
38144
|
-
if (!await
|
|
38670
|
+
const packageJsonPath = path27.join(scriptsDir, "package.json");
|
|
38671
|
+
if (!await import_fs_extra23.default.pathExists(packageJsonPath)) {
|
|
38145
38672
|
console.error(source_default.red(`package.json not found in ${scriptsDir}`));
|
|
38146
38673
|
return 1;
|
|
38147
38674
|
}
|
|
38148
|
-
const packageJson = await
|
|
38675
|
+
const packageJson = await import_fs_extra23.default.readJson(packageJsonPath);
|
|
38149
38676
|
if (!packageJson.scripts || !packageJson.scripts[scriptName]) {
|
|
38150
38677
|
console.error(source_default.red(`Script "${scriptName}" not found in package.json`));
|
|
38151
38678
|
return 1;
|
|
@@ -38168,7 +38695,7 @@ async function executeScript(scriptName, claudeDir) {
|
|
|
38168
38695
|
|
|
38169
38696
|
// src/commands/dynamic-scripts.ts
|
|
38170
38697
|
function getClaudeDir(parentOptions) {
|
|
38171
|
-
return parentOptions.claudeCodeFolder || parentOptions.folder ?
|
|
38698
|
+
return parentOptions.claudeCodeFolder || parentOptions.folder ? path28.resolve(parentOptions.claudeCodeFolder || parentOptions.folder) : path28.join(homedir(), ".claude");
|
|
38172
38699
|
}
|
|
38173
38700
|
async function registerDynamicScriptCommands(claudeCodeCmd, claudeDir) {
|
|
38174
38701
|
const scripts = await readScriptsPackageJson(claudeDir);
|
|
@@ -38230,13 +38757,21 @@ function registerAgentsCommands(cmd) {
|
|
|
38230
38757
|
codexFolder: parentOptions.codexFolder
|
|
38231
38758
|
});
|
|
38232
38759
|
});
|
|
38233
|
-
cmd.command("unify").description("Unify
|
|
38760
|
+
cmd.command("unify [scope]").description("Unify agent configuration into .agents (scope: global or repository; default: global)").action((scope, options, command) => {
|
|
38234
38761
|
const parentOptions = command.parent.opts();
|
|
38762
|
+
const selectedScope = scope ?? "global";
|
|
38763
|
+
if (selectedScope !== "global" && selectedScope !== "repository") {
|
|
38764
|
+
console.error(source_default.red(`Invalid unify scope: ${selectedScope}`));
|
|
38765
|
+
console.error(source_default.gray("Use `global` or `repository`."));
|
|
38766
|
+
process.exitCode = 1;
|
|
38767
|
+
return;
|
|
38768
|
+
}
|
|
38235
38769
|
return agentsUnifyCommand({
|
|
38236
|
-
folder: parentOptions.folder,
|
|
38770
|
+
folder: parentOptions.folder ?? (selectedScope === "repository" ? process.cwd() : undefined),
|
|
38237
38771
|
claudeCodeFolder: parentOptions.claudeCodeFolder,
|
|
38238
38772
|
codexFolder: parentOptions.codexFolder,
|
|
38239
|
-
agentsFolder: parentOptions.agentsFolder
|
|
38773
|
+
agentsFolder: parentOptions.agentsFolder,
|
|
38774
|
+
scope: selectedScope
|
|
38240
38775
|
});
|
|
38241
38776
|
});
|
|
38242
38777
|
cmd.command("codex-agents").description("Render shared Markdown agents from .agents/agents into Codex TOML custom agents").option("--overwrite", "Overwrite existing non-generated Codex agent files").action((options, command) => {
|
|
@@ -38249,6 +38784,12 @@ function registerAgentsCommands(cmd) {
|
|
|
38249
38784
|
overwrite: options.overwrite
|
|
38250
38785
|
});
|
|
38251
38786
|
});
|
|
38787
|
+
const configCmd = cmd.command("config").description("Manage cross-tool agent configuration data");
|
|
38788
|
+
const configUnifyCmd = configCmd.command("unify").description("Merge saved configuration data back into the current folders");
|
|
38789
|
+
configUnifyCmd.command("sessions").description("Import saved session history from configs and backups into current .claude/.codex/.agents folders").action((options, command) => {
|
|
38790
|
+
const folderOptions = readConfigOptions(command, options);
|
|
38791
|
+
return sessionsUnifyCommand(folderOptions);
|
|
38792
|
+
});
|
|
38252
38793
|
const proCmd = cmd.command("pro").description("Manage AIBlueprint CLI Premium features");
|
|
38253
38794
|
proCmd.command("activate [token]").description("Activate AIBlueprint CLI Premium with your access token").action((token) => {
|
|
38254
38795
|
proActivateCommand(token);
|
|
@@ -38289,6 +38830,7 @@ function registerAgentsCommands(cmd) {
|
|
|
38289
38830
|
backupLoadCommand({
|
|
38290
38831
|
folder: parentOptions.folder,
|
|
38291
38832
|
claudeCodeFolder: parentOptions.claudeCodeFolder,
|
|
38833
|
+
codexFolder: parentOptions.codexFolder,
|
|
38292
38834
|
agentsFolder: parentOptions.agentsFolder
|
|
38293
38835
|
});
|
|
38294
38836
|
});
|
|
@@ -38297,13 +38839,21 @@ function addConfigFolderOptions(cmd) {
|
|
|
38297
38839
|
return cmd.option("-f, --folder <path>", "Root folder that contains .claude/, .codex/, .agents/ (default: $HOME)").option("--claudeCodeFolder <path>", "Override Claude Code folder (default: {folder}/.claude)").option("--codexFolder <path>", "Override Codex folder (default: {folder}/.codex)").option("--agentsFolder <path>", "Override shared agents folder (default: {folder}/.agents)");
|
|
38298
38840
|
}
|
|
38299
38841
|
function readConfigOptions(command, options = {}) {
|
|
38300
|
-
const
|
|
38301
|
-
|
|
38842
|
+
const optionChain = [options];
|
|
38843
|
+
let current = command;
|
|
38844
|
+
while (current) {
|
|
38845
|
+
optionChain.push(current.opts());
|
|
38846
|
+
current = current.parent ?? null;
|
|
38847
|
+
}
|
|
38848
|
+
const findOption = (name) => {
|
|
38849
|
+
const value = optionChain.find((opts) => opts[name] !== undefined)?.[name];
|
|
38850
|
+
return typeof value === "string" ? value : undefined;
|
|
38851
|
+
};
|
|
38302
38852
|
return {
|
|
38303
|
-
folder:
|
|
38304
|
-
claudeCodeFolder:
|
|
38305
|
-
codexFolder:
|
|
38306
|
-
agentsFolder:
|
|
38853
|
+
folder: findOption("folder"),
|
|
38854
|
+
claudeCodeFolder: findOption("claudeCodeFolder"),
|
|
38855
|
+
codexFolder: findOption("codexFolder"),
|
|
38856
|
+
agentsFolder: findOption("agentsFolder")
|
|
38307
38857
|
};
|
|
38308
38858
|
}
|
|
38309
38859
|
var agentsCmd = program2.command("agents").description("AI coding configuration commands");
|