@axiomatic-labs/claudeflow 2.13.17 → 2.13.19
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 +72 -11
- package/package.json +1 -1
package/lib/install.js
CHANGED
|
@@ -154,7 +154,7 @@ async function run() {
|
|
|
154
154
|
copyDirSync(srcTemplates, dstTemplates);
|
|
155
155
|
}
|
|
156
156
|
materializeSharedAppendPrompt(cwd);
|
|
157
|
-
|
|
157
|
+
ensureDefaultClaudeMdRules(cwd);
|
|
158
158
|
propagateTemplateRules(cwd, srcTemplates);
|
|
159
159
|
|
|
160
160
|
// Copy template agents (only template-managed, preserve user agents)
|
|
@@ -991,17 +991,74 @@ function materializeSharedAppendPrompt(projectRoot) {
|
|
|
991
991
|
fs.copyFileSync(templatePath, outputPath);
|
|
992
992
|
}
|
|
993
993
|
|
|
994
|
-
//
|
|
995
|
-
//
|
|
996
|
-
//
|
|
997
|
-
//
|
|
998
|
-
|
|
994
|
+
// Inject the canonical claudeflow rules block into the project's CLAUDE.md.
|
|
995
|
+
//
|
|
996
|
+
// Three cases:
|
|
997
|
+
// 1. CLAUDE.md absent → create with the block plus user-content section
|
|
998
|
+
// 2. CLAUDE.md present, no sentinel, no opt-out → prepend the block,
|
|
999
|
+
// preserving every byte of the existing file
|
|
1000
|
+
// 3. CLAUDE.md present with sentinel → replace the block in place
|
|
1001
|
+
// (keeps future template revisions propagating idempotently)
|
|
1002
|
+
//
|
|
1003
|
+
// User opt-out: drop the literal string `claudeflow:default-rules:opt-out`
|
|
1004
|
+
// anywhere in CLAUDE.md (e.g. in a comment) to skip injection forever.
|
|
1005
|
+
//
|
|
1006
|
+
// The block is wrapped in HTML comments — markdown renders them invisibly
|
|
1007
|
+
// but they survive editor round-trips and remain machine-detectable.
|
|
1008
|
+
const CLAUDE_MD_INJECT_BEGIN = '<!-- claudeflow:default-rules:start (do not edit between markers) -->';
|
|
1009
|
+
const CLAUDE_MD_INJECT_END = '<!-- claudeflow:default-rules:end -->';
|
|
1010
|
+
const CLAUDE_MD_OPT_OUT = 'claudeflow:default-rules:opt-out';
|
|
1011
|
+
|
|
1012
|
+
function buildDefaultRulesBlock(projectRoot) {
|
|
999
1013
|
const templatePath = path.join(projectRoot, DEFAULT_CLAUDE_MD_TEMPLATE);
|
|
1000
|
-
if (!fs.existsSync(templatePath)) return
|
|
1014
|
+
if (!fs.existsSync(templatePath)) return null;
|
|
1015
|
+
let body = fs.readFileSync(templatePath, 'utf8');
|
|
1016
|
+
// Strip the leading `# CLAUDE.md` heading — when injected into an existing
|
|
1017
|
+
// file the heading would conflict with the user's own H1.
|
|
1018
|
+
body = body.replace(/^\s*#\s*CLAUDE\.md\s*\r?\n+/, '').trimEnd();
|
|
1019
|
+
return `${CLAUDE_MD_INJECT_BEGIN}\n${body}\n${CLAUDE_MD_INJECT_END}`;
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
function ensureDefaultClaudeMdRules(projectRoot) {
|
|
1023
|
+
const block = buildDefaultRulesBlock(projectRoot);
|
|
1024
|
+
if (!block) return { action: 'no-template' };
|
|
1025
|
+
|
|
1001
1026
|
const outputPath = path.join(projectRoot, DEFAULT_CLAUDE_MD_OUTPUT);
|
|
1002
|
-
|
|
1003
|
-
fs.
|
|
1004
|
-
|
|
1027
|
+
|
|
1028
|
+
if (!fs.existsSync(outputPath)) {
|
|
1029
|
+
fs.writeFileSync(outputPath, `${block}\n`);
|
|
1030
|
+
return { action: 'created' };
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
const existing = fs.readFileSync(outputPath, 'utf8');
|
|
1034
|
+
|
|
1035
|
+
if (existing.includes(CLAUDE_MD_OPT_OUT)) {
|
|
1036
|
+
return { action: 'opt-out' };
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
// The block always lives at the bottom. Two paths get us there:
|
|
1040
|
+
// - sentinels found at the bottom and content current → unchanged
|
|
1041
|
+
// - sentinels found anywhere else (top, middle, stale content) →
|
|
1042
|
+
// remove the old block and append a fresh one at the tail.
|
|
1043
|
+
// - sentinels absent → append for the first time.
|
|
1044
|
+
const beginIdx = existing.indexOf(CLAUDE_MD_INJECT_BEGIN);
|
|
1045
|
+
const endIdx = existing.indexOf(CLAUDE_MD_INJECT_END);
|
|
1046
|
+
let userContent;
|
|
1047
|
+
if (beginIdx !== -1 && endIdx !== -1 && endIdx > beginIdx) {
|
|
1048
|
+
const before = existing.slice(0, beginIdx);
|
|
1049
|
+
const after = existing.slice(endIdx + CLAUDE_MD_INJECT_END.length);
|
|
1050
|
+
userContent = `${before.replace(/\s+$/, '')}${after.startsWith('\n') ? '' : '\n'}${after}`.replace(/^\s+/, '').replace(/\s+$/, '');
|
|
1051
|
+
} else {
|
|
1052
|
+
userContent = existing.replace(/\s+$/, '');
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
const next = userContent.length === 0
|
|
1056
|
+
? `${block}\n`
|
|
1057
|
+
: `${userContent}\n\n${block}\n`;
|
|
1058
|
+
|
|
1059
|
+
if (next === existing) return { action: 'unchanged' };
|
|
1060
|
+
fs.writeFileSync(outputPath, next);
|
|
1061
|
+
return { action: beginIdx !== -1 ? 'updated' : 'injected' };
|
|
1005
1062
|
}
|
|
1006
1063
|
|
|
1007
1064
|
function isTemplateManagedAgent(agentName) {
|
|
@@ -1036,7 +1093,11 @@ function copyDirSync(src, dst, skipNames) {
|
|
|
1036
1093
|
module.exports = Object.assign(run, {
|
|
1037
1094
|
assertRequiredTemplateRules,
|
|
1038
1095
|
materializeSharedAppendPrompt,
|
|
1039
|
-
|
|
1096
|
+
ensureDefaultClaudeMdRules,
|
|
1097
|
+
buildDefaultRulesBlock,
|
|
1098
|
+
CLAUDE_MD_INJECT_BEGIN,
|
|
1099
|
+
CLAUDE_MD_INJECT_END,
|
|
1100
|
+
CLAUDE_MD_OPT_OUT,
|
|
1040
1101
|
isTemplateManagedAgent,
|
|
1041
1102
|
listTemplateManagedAgents,
|
|
1042
1103
|
mergeClaudeSettings,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axiomatic-labs/claudeflow",
|
|
3
|
-
"version": "2.13.
|
|
3
|
+
"version": "2.13.19",
|
|
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"
|