@axiomatic-labs/claudeflow 2.43.31 → 2.43.33
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 +99 -46
- package/lib/version.js +2 -2
- package/package.json +1 -1
package/lib/install.js
CHANGED
|
@@ -102,70 +102,102 @@ function syncClaudeMd(cwd, snippetPath) {
|
|
|
102
102
|
// Place + merge the framework from an extracted payload dir into a project. Pure filesystem, no network —
|
|
103
103
|
// so it is testable on a throwaway dir.
|
|
104
104
|
function installFromPayload(src, cwd) {
|
|
105
|
-
const out = { playbooks: 0, scripts: 0, skills: 0, agents: 0, claudeMd: false };
|
|
105
|
+
const out = { playbooks: 0, scripts: 0, skills: 0, agents: 0, claudeMd: false, failed: [] };
|
|
106
|
+
// Each placement step is ISOLATED: a failure in one (a copy error, a permission hiccup, a weird file in the
|
|
107
|
+
// user's tree) must NOT abort the rest — above all it must not skip the settings/env + CLAUDE.md config, the
|
|
108
|
+
// two steps a user most needs (the env block wires agent-teams + the autocompact window, etc.). Before this,
|
|
109
|
+
// any throw in steps 1–4 silently left settings/CLAUDE.md unconfigured. Each step records its name on failure
|
|
110
|
+
// so `run()` can warn instead of reporting a clean success over a partial install.
|
|
111
|
+
const step = (name, fn) => { try { fn(); } catch { out.failed.push(name); } };
|
|
106
112
|
|
|
107
113
|
// 1) Playbooks — always refreshed (shared system).
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
+
step('playbooks', () => {
|
|
115
|
+
const srcPlaybooks = path.join(src, '.claudeflow', 'playbooks');
|
|
116
|
+
if (fs.existsSync(srcPlaybooks)) {
|
|
117
|
+
const dst = path.join(cwd, '.claudeflow', 'playbooks');
|
|
118
|
+
rmrf(dst); copyDir(srcPlaybooks, dst);
|
|
119
|
+
out.playbooks = countFiles(dst);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
114
122
|
|
|
115
123
|
// 2) Configs — per-project ones create-if-absent (never clobber a customized brand); shared refresh.
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
124
|
+
step('configs', () => {
|
|
125
|
+
fs.mkdirSync(path.join(cwd, '.claudeflow'), { recursive: true });
|
|
126
|
+
for (const c of PER_PROJECT_CONFIGS) {
|
|
127
|
+
const s = path.join(src, '.claudeflow', c), d = path.join(cwd, '.claudeflow', c);
|
|
128
|
+
if (fs.existsSync(s) && !fs.existsSync(d)) fs.copyFileSync(s, d);
|
|
129
|
+
}
|
|
130
|
+
for (const c of SHARED_CONFIGS) {
|
|
131
|
+
const s = path.join(src, '.claudeflow', c);
|
|
132
|
+
if (fs.existsSync(s)) fs.copyFileSync(s, path.join(cwd, '.claudeflow', c));
|
|
133
|
+
}
|
|
134
|
+
});
|
|
125
135
|
|
|
126
|
-
// 3) Scripts (hooks + scans + servers) — always refreshed.
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const
|
|
130
|
-
fs.
|
|
131
|
-
|
|
132
|
-
|
|
136
|
+
// 3) Scripts (hooks + scans + servers) — always refreshed. Per-file isolation so ONE bad file (a socket, a
|
|
137
|
+
// permission denial) can't abort the whole copy — let alone the later settings/CLAUDE.md steps.
|
|
138
|
+
step('scripts', () => {
|
|
139
|
+
const srcScripts = path.join(src, 'scripts', 'claudeflow');
|
|
140
|
+
if (fs.existsSync(srcScripts)) {
|
|
141
|
+
const dst = path.join(cwd, 'scripts', 'claudeflow');
|
|
142
|
+
fs.mkdirSync(dst, { recursive: true });
|
|
143
|
+
for (const e of fs.readdirSync(srcScripts)) {
|
|
144
|
+
try { fs.copyFileSync(path.join(srcScripts, e), path.join(dst, e)); out.scripts++; } catch {}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
});
|
|
133
148
|
|
|
134
149
|
// 4) Skills — replace each shipped claudeflow-* skill; preserve the user's own skills.
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
150
|
+
step('skills', () => {
|
|
151
|
+
const srcSkills = path.join(src, '.claude', 'skills');
|
|
152
|
+
if (fs.existsSync(srcSkills)) {
|
|
153
|
+
const dst = path.join(cwd, '.claude', 'skills');
|
|
154
|
+
fs.mkdirSync(dst, { recursive: true });
|
|
155
|
+
for (const e of fs.readdirSync(srcSkills, { withFileTypes: true })) {
|
|
156
|
+
if (!e.isDirectory() || !e.name.startsWith('claudeflow-')) continue;
|
|
157
|
+
const d = path.join(dst, e.name);
|
|
158
|
+
try { rmrf(d); copyDir(path.join(srcSkills, e.name), d); out.skills++; } catch {}
|
|
159
|
+
}
|
|
143
160
|
}
|
|
144
|
-
}
|
|
161
|
+
});
|
|
145
162
|
|
|
146
163
|
// 4b) Agents — replace each shipped claudeflow-* agent; preserve the user's own agents.
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
164
|
+
step('agents', () => {
|
|
165
|
+
const srcAgents = path.join(src, '.claude', 'agents');
|
|
166
|
+
if (fs.existsSync(srcAgents)) {
|
|
167
|
+
const dst = path.join(cwd, '.claude', 'agents');
|
|
168
|
+
fs.mkdirSync(dst, { recursive: true });
|
|
169
|
+
for (const e of fs.readdirSync(srcAgents, { withFileTypes: true })) {
|
|
170
|
+
if (!e.isFile() || !e.name.startsWith('claudeflow-') || !e.name.endsWith('.md')) continue;
|
|
171
|
+
try { fs.copyFileSync(path.join(srcAgents, e.name), path.join(dst, e.name)); out.agents++; } catch {}
|
|
172
|
+
}
|
|
154
173
|
}
|
|
155
|
-
}
|
|
174
|
+
});
|
|
156
175
|
|
|
157
|
-
// 5) settings.json
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
176
|
+
// 5) settings.json — MERGE the shipped hooks + env (add-if-absent) into the user's settings (never clobber).
|
|
177
|
+
// ALWAYS runs (isolated above) — this is what wires CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS et al.
|
|
178
|
+
step('settings', () => {
|
|
179
|
+
const srcSettings = path.join(src, '.claude', 'settings.json');
|
|
180
|
+
if (fs.existsSync(srcSettings)) {
|
|
181
|
+
mergeSettings(cwd, JSON.parse(fs.readFileSync(srcSettings, 'utf8')));
|
|
182
|
+
}
|
|
183
|
+
});
|
|
162
184
|
|
|
163
185
|
// 6) CLAUDE.md — upsert the managed guidance block between markers (idempotent; updates propagate on re-install).
|
|
164
|
-
|
|
186
|
+
step('claude-md', () => {
|
|
187
|
+
out.claudeMd = syncClaudeMd(cwd, path.join(src, 'assets', 'CLAUDE.snippet.md'));
|
|
188
|
+
});
|
|
165
189
|
|
|
166
190
|
return out;
|
|
167
191
|
}
|
|
168
192
|
|
|
193
|
+
// `a < b` for `x.y.z` versions (numeric, missing parts = 0). Used to detect a STALE npx-cached CLI.
|
|
194
|
+
function semverLt(a, b) {
|
|
195
|
+
const pa = String(a).split('.').map(n => parseInt(n, 10) || 0);
|
|
196
|
+
const pb = String(b).split('.').map(n => parseInt(n, 10) || 0);
|
|
197
|
+
for (let i = 0; i < 3; i++) { if ((pa[i] || 0) < (pb[i] || 0)) return true; if ((pa[i] || 0) > (pb[i] || 0)) return false; }
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
|
|
169
201
|
async function run() {
|
|
170
202
|
const current = readLocalVersion();
|
|
171
203
|
ui.banner(current || undefined);
|
|
@@ -181,6 +213,24 @@ async function run() {
|
|
|
181
213
|
const version = (release.tag_name || '').replace(/^v/, '')
|
|
182
214
|
|| asset.name.replace(/^claudeflow-?v?/, '').replace(/\.zip$/, '');
|
|
183
215
|
|
|
216
|
+
// STALE-npx-CACHE GUARD. This CLI binary is whatever npx ran — and `npx <pkg> install` (no @version) will
|
|
217
|
+
// happily REUSE a cached OLD CLI without checking npm for a newer one. An old CLI still downloads the fresh
|
|
218
|
+
// release ZIP (so hooks/playbooks/scripts update — looks like it worked) but its `mergeSettings` predates
|
|
219
|
+
// newer placement logic (e.g. the `env` block merge added after v2.42.0), so config like the agent-teams env
|
|
220
|
+
// vars is SILENTLY skipped — hooks land, env never does. If this CLI's own version is OLDER than the release
|
|
221
|
+
// it's installing, that's exactly the stale-cache case → make it LOUD (the old CLI itself can't, but once a
|
|
222
|
+
// user is on a guarded version this catches every future recurrence).
|
|
223
|
+
let staleCli = false;
|
|
224
|
+
try {
|
|
225
|
+
const cliVersion = require('../package.json').version;
|
|
226
|
+
staleCli = semverLt(cliVersion, version);
|
|
227
|
+
if (staleCli) {
|
|
228
|
+
ui.warn(`Stale CLI: npx is running a CACHED v${cliVersion} but the latest release is v${version}.`);
|
|
229
|
+
ui.warn(` An old CLI updates hooks but can SKIP config (the agent-teams env vars, etc.). To install with`);
|
|
230
|
+
ui.warn(` the matching CLI: ${ui.BOLD}npx @axiomatic-labs/claudeflow@latest install${ui.RESET} (or clear the npx cache: ${ui.BOLD}npx clear-npx-cache${ui.RESET}).`);
|
|
231
|
+
}
|
|
232
|
+
} catch {}
|
|
233
|
+
|
|
184
234
|
ui.step(`Downloading ${asset.name}...`);
|
|
185
235
|
const zipBuffer = await downloadReleaseAsset(asset, token);
|
|
186
236
|
|
|
@@ -200,6 +250,9 @@ async function run() {
|
|
|
200
250
|
ui.success(`claudeflow v${version} installed`);
|
|
201
251
|
ui.info(` ${summary.playbooks} playbooks · ${summary.scripts} scripts · ${summary.skills} skills`
|
|
202
252
|
+ (summary.claudeMd ? ' · CLAUDE.md guidance synced' : ''));
|
|
253
|
+
if (summary.failed && summary.failed.length) {
|
|
254
|
+
ui.warn(` some steps did not complete: ${summary.failed.join(', ')}. Re-run \`npx @axiomatic-labs/claudeflow@latest install\` (the @latest avoids a stale npx cache).`);
|
|
255
|
+
}
|
|
203
256
|
ui.done(`Describe a change and the ${ui.BOLD}claudeflow-implementer${ui.RESET} agent will build it.`);
|
|
204
257
|
}
|
|
205
258
|
|
package/lib/version.js
CHANGED
|
@@ -31,7 +31,7 @@ async function run() {
|
|
|
31
31
|
if (local) {
|
|
32
32
|
ui.info(`Installed: ${local}`);
|
|
33
33
|
} else {
|
|
34
|
-
ui.warn('Not installed. Run: npx @axiomatic-labs/claudeflow install');
|
|
34
|
+
ui.warn('Not installed. Run: npx @axiomatic-labs/claudeflow@latest install');
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
const token = getGitHubToken();
|
|
@@ -50,7 +50,7 @@ async function run() {
|
|
|
50
50
|
if (local && local === latest) {
|
|
51
51
|
ui.success('Up to date.');
|
|
52
52
|
} else if (local) {
|
|
53
|
-
ui.warn('Update available. Run: npx @axiomatic-labs/claudeflow install');
|
|
53
|
+
ui.warn('Update available. Run: npx @axiomatic-labs/claudeflow@latest install (the @latest avoids a stale npx cache)');
|
|
54
54
|
}
|
|
55
55
|
} catch (err) {
|
|
56
56
|
ui.error(`Could not fetch latest release: ${err.message}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axiomatic-labs/claudeflow",
|
|
3
|
-
"version": "2.43.
|
|
3
|
+
"version": "2.43.33",
|
|
4
4
|
"description": "Claudeflow — AI-powered development toolkit for Claude Code. Skills, agents, hooks, and quality gates that ship production apps.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"claudeflow": "./bin/cli.js"
|