@axiomatic-labs/claudeflow 2.49.11 → 2.49.12
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/lib/install.js +107 -5
- package/package.json +1 -1
package/lib/install.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const os = require('os');
|
|
4
|
+
const crypto = require('crypto');
|
|
4
5
|
const { execSync } = require('child_process');
|
|
5
6
|
const { requireAuth } = require('./auth.js');
|
|
6
7
|
const { getLatestRelease, downloadReleaseAsset } = require('./download.js');
|
|
@@ -41,6 +42,83 @@ function copyDir(src, dst) {
|
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
|
|
45
|
+
function copyPath(src, dst) {
|
|
46
|
+
const st = fs.statSync(src);
|
|
47
|
+
if (st.isDirectory()) copyDir(src, dst);
|
|
48
|
+
else if (st.isFile()) {
|
|
49
|
+
fs.mkdirSync(path.dirname(dst), { recursive: true });
|
|
50
|
+
fs.copyFileSync(src, dst);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function pathHash(p) {
|
|
55
|
+
if (!fs.existsSync(p)) return null;
|
|
56
|
+
const h = crypto.createHash('sha256');
|
|
57
|
+
const walk = (cur, rel) => {
|
|
58
|
+
const st = fs.statSync(cur);
|
|
59
|
+
if (st.isDirectory()) {
|
|
60
|
+
h.update(`dir:${rel}\n`);
|
|
61
|
+
for (const name of fs.readdirSync(cur).sort()) walk(path.join(cur, name), path.join(rel, name));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (!st.isFile()) return;
|
|
65
|
+
h.update(`file:${rel}\n`);
|
|
66
|
+
h.update(fs.readFileSync(cur));
|
|
67
|
+
h.update('\n');
|
|
68
|
+
};
|
|
69
|
+
walk(p, '');
|
|
70
|
+
return h.digest('hex');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function syncManagedGlobalDir(srcDir, dstDir, backupRoot, filter) {
|
|
74
|
+
const out = { synced: 0, changed: 0, backups: 0, failed: 0 };
|
|
75
|
+
if (!fs.existsSync(srcDir)) return out;
|
|
76
|
+
fs.mkdirSync(dstDir, { recursive: true });
|
|
77
|
+
for (const e of fs.readdirSync(srcDir, { withFileTypes: true })) {
|
|
78
|
+
if (!filter(e)) continue;
|
|
79
|
+
const s = path.join(srcDir, e.name);
|
|
80
|
+
const d = path.join(dstDir, e.name);
|
|
81
|
+
try {
|
|
82
|
+
out.synced++;
|
|
83
|
+
if (pathHash(s) === pathHash(d)) continue;
|
|
84
|
+
if (fs.existsSync(d)) {
|
|
85
|
+
copyPath(d, path.join(backupRoot, path.basename(dstDir), e.name));
|
|
86
|
+
out.backups++;
|
|
87
|
+
}
|
|
88
|
+
rmrf(d);
|
|
89
|
+
copyPath(s, d);
|
|
90
|
+
out.changed++;
|
|
91
|
+
} catch {
|
|
92
|
+
out.failed++;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function syncGlobalClaudeArtifacts(src, homeDir = os.homedir()) {
|
|
99
|
+
const stamp = new Date().toISOString().replace(/\D/g, '').slice(0, 14) + '-' + process.pid;
|
|
100
|
+
const backupRoot = path.join(homeDir, '.claude', 'backup', `claudeflow-install-${stamp}`);
|
|
101
|
+
const skillStats = syncManagedGlobalDir(
|
|
102
|
+
path.join(src, '.claude', 'skills'),
|
|
103
|
+
path.join(homeDir, '.claude', 'skills'),
|
|
104
|
+
backupRoot,
|
|
105
|
+
e => e.isDirectory() && e.name.startsWith('claudeflow-'),
|
|
106
|
+
);
|
|
107
|
+
const agentStats = syncManagedGlobalDir(
|
|
108
|
+
path.join(src, '.claude', 'agents'),
|
|
109
|
+
path.join(homeDir, '.claude', 'agents'),
|
|
110
|
+
backupRoot,
|
|
111
|
+
e => e.isFile() && e.name.startsWith('claudeflow-') && e.name.endsWith('.md'),
|
|
112
|
+
);
|
|
113
|
+
return {
|
|
114
|
+
skills: skillStats.synced,
|
|
115
|
+
agents: agentStats.synced,
|
|
116
|
+
changed: skillStats.changed + agentStats.changed,
|
|
117
|
+
backups: skillStats.backups + agentStats.backups,
|
|
118
|
+
failed: skillStats.failed + agentStats.failed,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
44
122
|
function countFiles(dir) {
|
|
45
123
|
let n = 0;
|
|
46
124
|
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
@@ -295,13 +373,18 @@ function syncAgentsMd(cwd, snippetPath) {
|
|
|
295
373
|
}
|
|
296
374
|
|
|
297
375
|
// Place + merge the framework from an extracted payload dir into a project. Pure filesystem, no network —
|
|
298
|
-
// so it is testable on a throwaway dir.
|
|
299
|
-
|
|
376
|
+
// so it is testable on a throwaway dir. The real CLI turns on `syncGlobalClaude` so stale personal
|
|
377
|
+
// Claude Code skills/agents cannot shadow the project-local copy; tests keep it off unless explicit.
|
|
378
|
+
function installFromPayload(src, cwd, options = {}) {
|
|
300
379
|
const out = {
|
|
301
380
|
playbooks: 0,
|
|
302
381
|
scripts: 0,
|
|
303
382
|
skills: 0,
|
|
304
383
|
agents: 0,
|
|
384
|
+
globalSkills: 0,
|
|
385
|
+
globalAgents: 0,
|
|
386
|
+
globalChanged: 0,
|
|
387
|
+
globalBackups: 0,
|
|
305
388
|
codexSkills: 0,
|
|
306
389
|
codexAgents: 0,
|
|
307
390
|
codexHooks: false,
|
|
@@ -385,7 +468,20 @@ function installFromPayload(src, cwd) {
|
|
|
385
468
|
}
|
|
386
469
|
});
|
|
387
470
|
|
|
388
|
-
// 4c)
|
|
471
|
+
// 4c) Personal Claude Code cache repair — Claude prioritizes ~/.claude skills/agents over project-local
|
|
472
|
+
// ones. A stale personal claudeflow-* copy shadows the version just installed in this project, so the real
|
|
473
|
+
// CLI refreshes only our namespaced personal artifacts and backs up any changed copy first.
|
|
474
|
+
step('global-claude-artifacts', () => {
|
|
475
|
+
if (options.syncGlobalClaude !== true) return;
|
|
476
|
+
const r = syncGlobalClaudeArtifacts(src, options.globalHome || os.homedir());
|
|
477
|
+
out.globalSkills = r.skills;
|
|
478
|
+
out.globalAgents = r.agents;
|
|
479
|
+
out.globalChanged = r.changed;
|
|
480
|
+
out.globalBackups = r.backups;
|
|
481
|
+
if (r.failed) out.failed.push(`global-claude-artifacts:${r.failed}`);
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
// 4d) Codex skills — replace shipped claudeflow-* skills in .agents; preserve user skills.
|
|
389
485
|
step('codex-skills', () => {
|
|
390
486
|
const srcSkills = path.join(src, '.agents', 'skills');
|
|
391
487
|
if (fs.existsSync(srcSkills)) {
|
|
@@ -399,7 +495,7 @@ function installFromPayload(src, cwd) {
|
|
|
399
495
|
}
|
|
400
496
|
});
|
|
401
497
|
|
|
402
|
-
//
|
|
498
|
+
// 4e) Codex agents — replace shipped claudeflow-*.toml agents; preserve user agents.
|
|
403
499
|
step('codex-agents', () => {
|
|
404
500
|
const srcAgents = path.join(src, '.codex', 'agents');
|
|
405
501
|
if (fs.existsSync(srcAgents)) {
|
|
@@ -537,13 +633,18 @@ async function run() {
|
|
|
537
633
|
execSync(`unzip -qq -o "${tmpZip}" -d "${tmp}"`, { stdio: 'ignore' });
|
|
538
634
|
|
|
539
635
|
ui.step('Installing framework...');
|
|
540
|
-
const summary = installFromPayload(tmp, cwd);
|
|
636
|
+
const summary = installFromPayload(tmp, cwd, { syncGlobalClaude: process.env.CLAUDEFLOW_NO_GLOBAL_SYNC !== '1' });
|
|
541
637
|
writeLocalVersion(`v${version}`);
|
|
542
638
|
|
|
543
639
|
try { rmrf(tmp); fs.rmSync(tmpZip, { force: true }); } catch {}
|
|
544
640
|
|
|
545
641
|
ui.success(`claudeflow v${version} installed`);
|
|
546
642
|
ui.info(` ${summary.playbooks} playbooks · ${summary.scripts} scripts · ${summary.skills} skills`
|
|
643
|
+
+ (summary.globalSkills || summary.globalAgents
|
|
644
|
+
? ` · global Claude repaired (${summary.globalSkills} skills, ${summary.globalAgents} agents`
|
|
645
|
+
+ (summary.globalBackups ? `, ${summary.globalBackups} backups` : '')
|
|
646
|
+
+ ')'
|
|
647
|
+
: '')
|
|
547
648
|
+ (summary.codexSkills ? ` · ${summary.codexSkills} Codex skills` : '')
|
|
548
649
|
+ (summary.codexAgents ? ` · ${summary.codexAgents} Codex agents` : '')
|
|
549
650
|
+ (summary.codexHooks ? ' · Codex hooks merged' : '')
|
|
@@ -563,6 +664,7 @@ module.exports.installFromPayload = installFromPayload;
|
|
|
563
664
|
module.exports.mergeSettings = mergeSettings;
|
|
564
665
|
module.exports.syncClaudeMd = syncClaudeMd;
|
|
565
666
|
module.exports.syncAgentsMd = syncAgentsMd;
|
|
667
|
+
module.exports.syncGlobalClaudeArtifacts = syncGlobalClaudeArtifacts;
|
|
566
668
|
module.exports.mergeMcp = mergeMcp;
|
|
567
669
|
module.exports.mergeGitignore = mergeGitignore;
|
|
568
670
|
module.exports.mergeCodexHooks = mergeCodexHooks;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axiomatic-labs/claudeflow",
|
|
3
|
-
"version": "2.49.
|
|
3
|
+
"version": "2.49.12",
|
|
4
4
|
"description": "Claudeflow — AI-powered development toolkit for Claude Code and Codex. Skills, agents, hooks, and quality gates that ship production apps.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"claudeflow": "./bin/cli.js"
|