@axiomatic-labs/claudeflow 2.12.84 → 2.12.85
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 +75 -2
- package/package.json +1 -1
package/lib/install.js
CHANGED
|
@@ -13,6 +13,8 @@ const TEMPLATE_AGENTS = new Set(['claudeflow-explorer', 'claudeflow-planner', 'e
|
|
|
13
13
|
const TEMPLATE_MANAGED_MANIFEST = path.join('.claudeflow', 'config', 'template-managed-manifest.json');
|
|
14
14
|
const CLAUDE_BACKUP_ROOT = '.claudeflow-backups';
|
|
15
15
|
const REQUIRED_TEMPLATE_RULES = ['claudeflow-implementation.md'];
|
|
16
|
+
const TEMPLATE_MANAGED_SETTINGS_KEYS = ['$schema', 'enabledMcpjsonServers', 'env', 'permissions', 'hooks'];
|
|
17
|
+
const TEMPLATE_SEEDED_SETTINGS_KEYS = new Set(['statusLine']);
|
|
16
18
|
|
|
17
19
|
async function run() {
|
|
18
20
|
const current = readLocalVersion();
|
|
@@ -71,12 +73,13 @@ async function run() {
|
|
|
71
73
|
const staleManagedPaths = [...previousManagedPaths].filter((relPath) => !nextManagedPaths.has(relPath));
|
|
72
74
|
staleRemovedCount = pruneStaleManagedPaths(cwd, staleManagedPaths);
|
|
73
75
|
|
|
74
|
-
//
|
|
76
|
+
// Merge settings.json so template-managed keys refresh on update while
|
|
77
|
+
// preserving user customizations like custom statusLine commands.
|
|
75
78
|
const srcSettings = path.join(srcClaude, 'settings.json');
|
|
76
79
|
const dstSettings = path.join(cwd, '.claude', 'settings.json');
|
|
77
80
|
fs.mkdirSync(path.join(cwd, '.claude'), { recursive: true });
|
|
78
81
|
if (fs.existsSync(srcSettings)) {
|
|
79
|
-
|
|
82
|
+
syncClaudeSettings(srcSettings, dstSettings);
|
|
80
83
|
}
|
|
81
84
|
|
|
82
85
|
// Upsert playwright entry in .mcp.json with project-specific CDP port.
|
|
@@ -247,6 +250,7 @@ async function run() {
|
|
|
247
250
|
ui.success(`${docCount} docs updated`);
|
|
248
251
|
ui.success(`${staleRemovedCount} stale template-managed files removed`);
|
|
249
252
|
ui.success(`Template-managed manifest updated (${managedPathCount} paths)`);
|
|
253
|
+
ui.info('Default Claude Code status line is seeded when missing. Existing custom statusLine settings are preserved on update and can be overridden in .claude/settings.local.json.');
|
|
250
254
|
if (backupPath) {
|
|
251
255
|
ui.success(`Backup created: ${path.relative(cwd, backupPath)}`);
|
|
252
256
|
}
|
|
@@ -261,6 +265,7 @@ async function run() {
|
|
|
261
265
|
ui.success(`${hookCount} hooks installed`);
|
|
262
266
|
ui.success(`${docCount} docs installed`);
|
|
263
267
|
ui.success(`Template-managed manifest written (${managedPathCount} paths)`);
|
|
268
|
+
ui.info('Default Claude Code status line installed. Override it in .claude/settings.json or .claude/settings.local.json.');
|
|
264
269
|
if (backupPath) {
|
|
265
270
|
ui.success(`Backup created: ${path.relative(cwd, backupPath)}`);
|
|
266
271
|
}
|
|
@@ -333,6 +338,73 @@ function showGettingStarted(cwd) {
|
|
|
333
338
|
console.log('');
|
|
334
339
|
}
|
|
335
340
|
|
|
341
|
+
function syncClaudeSettings(srcSettingsPath, dstSettingsPath) {
|
|
342
|
+
const templateSettings = readJsonObject(srcSettingsPath, {
|
|
343
|
+
label: 'template .claude/settings.json',
|
|
344
|
+
throwOnInvalid: true,
|
|
345
|
+
});
|
|
346
|
+
const existingSettings = readJsonObject(dstSettingsPath, {
|
|
347
|
+
label: 'existing .claude/settings.json',
|
|
348
|
+
warnOnInvalid: true,
|
|
349
|
+
}) || {};
|
|
350
|
+
const mergedSettings = mergeClaudeSettings(templateSettings, existingSettings);
|
|
351
|
+
fs.writeFileSync(dstSettingsPath, `${JSON.stringify(mergedSettings, null, 2)}\n`);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function mergeClaudeSettings(templateSettings, existingSettings = {}) {
|
|
355
|
+
const template = isPlainObject(templateSettings) ? templateSettings : {};
|
|
356
|
+
const existing = isPlainObject(existingSettings) ? existingSettings : {};
|
|
357
|
+
const merged = {};
|
|
358
|
+
|
|
359
|
+
for (const [key, value] of Object.entries(template)) {
|
|
360
|
+
if (TEMPLATE_MANAGED_SETTINGS_KEYS.includes(key)) {
|
|
361
|
+
merged[key] = cloneJson(value);
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
if (TEMPLATE_SEEDED_SETTINGS_KEYS.has(key)) {
|
|
365
|
+
merged[key] = Object.prototype.hasOwnProperty.call(existing, key)
|
|
366
|
+
? cloneJson(existing[key])
|
|
367
|
+
: cloneJson(value);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
for (const [key, value] of Object.entries(existing)) {
|
|
372
|
+
if (Object.prototype.hasOwnProperty.call(merged, key)) continue;
|
|
373
|
+
if (TEMPLATE_MANAGED_SETTINGS_KEYS.includes(key)) continue;
|
|
374
|
+
merged[key] = cloneJson(value);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return merged;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function readJsonObject(filePath, options = {}) {
|
|
381
|
+
if (!fs.existsSync(filePath)) return null;
|
|
382
|
+
const { label = filePath, throwOnInvalid = false, warnOnInvalid = false } = options;
|
|
383
|
+
|
|
384
|
+
try {
|
|
385
|
+
const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
386
|
+
if (isPlainObject(parsed)) return parsed;
|
|
387
|
+
|
|
388
|
+
const message = `${label} must contain a top-level JSON object`;
|
|
389
|
+
if (throwOnInvalid) throw new Error(message);
|
|
390
|
+
if (warnOnInvalid) ui.warn(`${message}. Replacing it with template-managed defaults.`);
|
|
391
|
+
return null;
|
|
392
|
+
} catch (error) {
|
|
393
|
+
if (throwOnInvalid) throw error;
|
|
394
|
+
if (warnOnInvalid) ui.warn(`${label} is invalid JSON. Replacing it with template-managed defaults.`);
|
|
395
|
+
return null;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function isPlainObject(value) {
|
|
400
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function cloneJson(value) {
|
|
404
|
+
if (value === undefined) return undefined;
|
|
405
|
+
return JSON.parse(JSON.stringify(value));
|
|
406
|
+
}
|
|
407
|
+
|
|
336
408
|
// Install ast-grep CLI, uv, and Serena MCP for runtime and analysis.
|
|
337
409
|
// All steps are best-effort — failures warn but never block the install.
|
|
338
410
|
function installAnalysisTools() {
|
|
@@ -756,4 +828,5 @@ function copyDirSync(src, dst, skipNames) {
|
|
|
756
828
|
|
|
757
829
|
module.exports = Object.assign(run, {
|
|
758
830
|
assertRequiredTemplateRules,
|
|
831
|
+
mergeClaudeSettings,
|
|
759
832
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axiomatic-labs/claudeflow",
|
|
3
|
-
"version": "2.12.
|
|
3
|
+
"version": "2.12.85",
|
|
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"
|