@axiomatic-labs/claudeflow 2.35.14 → 2.35.16

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.
Files changed (2) hide show
  1. package/lib/install.js +31 -9
  2. package/package.json +1 -1
package/lib/install.js CHANGED
@@ -10,10 +10,12 @@ const ui = require('./ui.js');
10
10
  // claudeflow installs a small, namespaced footprint. Most of it is self-contained files that are simply
11
11
  // PLACED (playbooks, scripts, skills) — those can't conflict with the user's project. The only things
12
12
  // that need a MERGE (never a clobber) are .claude/settings.json (register our hooks alongside theirs)
13
- // and CLAUDE.md (append our guidance block). That merge lives here, in Node, so install works on every
13
+ // and CLAUDE.md (upsert our guidance block between markers user content outside stays untouched). That
14
+ // merge lives here, in Node, so install works on every
14
15
  // platform with no shell dependency. The GitHub auth gate (auth.js/download.js) is untouched.
15
16
 
16
17
  const CLAUDE_MARK = '<!-- claudeflow:begin -->';
18
+ const CLAUDE_END = '<!-- claudeflow:end -->';
17
19
  const HOOK_TAG = 'scripts/claudeflow/hook_'; // identifies OUR hook entries in settings.json
18
20
  const PER_PROJECT_CONFIGS = ['brand.json', 'risk-signals.json']; // create-if-absent, never clobber
19
21
  const SHARED_CONFIGS = ['playbook-map.json', 'agent-map.json']; // always refreshed (shared system)
@@ -60,13 +62,32 @@ function mergeSettings(cwd, payloadSettings) {
60
62
  fs.writeFileSync(sp, JSON.stringify(data, null, 2) + '\n');
61
63
  }
62
64
 
63
- function appendClaudeMd(cwd, snippetPath) {
65
+ // UPSERT the claudeflow guidance block. The snippet is a self-contained `<!-- claudeflow:begin -->…<!-- end -->`
66
+ // region; everything OUTSIDE the markers is the user's own CLAUDE.md and is never touched. Behavior:
67
+ // • no CLAUDE.md → create it with the block
68
+ // • CLAUDE.md, no block yet → append the block (preserve the user's content)
69
+ // • CLAUDE.md WITH the block → REPLACE the marked region in place, so guidance updates PROPAGATE on `update`
70
+ // (the old code appended-once and never refreshed → a stale project never got new disciplines).
71
+ // • begin marker but no end (corrupted) → leave it untouched (don't risk eating user content)
72
+ function syncClaudeMd(cwd, snippetPath) {
64
73
  if (!fs.existsSync(snippetPath)) return false;
65
74
  const target = path.join(cwd, 'CLAUDE.md');
66
- if (fs.existsSync(target) && fs.readFileSync(target, 'utf8').includes(CLAUDE_MARK)) return false;
67
- const snippet = fs.readFileSync(snippetPath, 'utf8');
68
- const prefix = fs.existsSync(target) ? '\n' : '';
69
- fs.appendFileSync(target, prefix + snippet);
75
+ const block = fs.readFileSync(snippetPath, 'utf8').trim();
76
+ if (!fs.existsSync(target)) {
77
+ fs.writeFileSync(target, block + '\n');
78
+ return true;
79
+ }
80
+ const cur = fs.readFileSync(target, 'utf8');
81
+ const b = cur.indexOf(CLAUDE_MARK);
82
+ if (b === -1) {
83
+ fs.writeFileSync(target, cur.replace(/\s*$/, '') + '\n\n' + block + '\n');
84
+ return true;
85
+ }
86
+ const e = cur.indexOf(CLAUDE_END, b);
87
+ if (e === -1) return false; // begin without end → corrupt region; don't clobber
88
+ const updated = cur.slice(0, b) + block + cur.slice(e + CLAUDE_END.length);
89
+ if (updated === cur) return false; // already current
90
+ fs.writeFileSync(target, updated);
70
91
  return true;
71
92
  }
72
93
 
@@ -131,8 +152,8 @@ function installFromPayload(src, cwd) {
131
152
  try { mergeSettings(cwd, JSON.parse(fs.readFileSync(srcSettings, 'utf8'))); } catch {}
132
153
  }
133
154
 
134
- // 6) CLAUDE.md — append the guidance block (idempotent).
135
- out.claudeMd = appendClaudeMd(cwd, path.join(src, 'assets', 'CLAUDE.snippet.md'));
155
+ // 6) CLAUDE.md — upsert the managed guidance block between markers (idempotent; updates propagate on re-install).
156
+ out.claudeMd = syncClaudeMd(cwd, path.join(src, 'assets', 'CLAUDE.snippet.md'));
136
157
 
137
158
  return out;
138
159
  }
@@ -170,10 +191,11 @@ async function run() {
170
191
 
171
192
  ui.success(`claudeflow v${version} installed`);
172
193
  ui.info(` ${summary.playbooks} playbooks · ${summary.scripts} scripts · ${summary.skills} skills`
173
- + (summary.claudeMd ? ' · CLAUDE.md guidance added' : ''));
194
+ + (summary.claudeMd ? ' · CLAUDE.md guidance synced' : ''));
174
195
  ui.done(`Describe a change and the ${ui.BOLD}claudeflow-implement${ui.RESET} skill will drive it.`);
175
196
  }
176
197
 
177
198
  module.exports = run;
178
199
  module.exports.installFromPayload = installFromPayload;
179
200
  module.exports.mergeSettings = mergeSettings;
201
+ module.exports.syncClaudeMd = syncClaudeMd;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axiomatic-labs/claudeflow",
3
- "version": "2.35.14",
3
+ "version": "2.35.16",
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"