cc-devflow 4.1.2 → 4.1.4
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/.claude/CLAUDE.md +3 -2
- package/.claude/commands/flow/dev.md +1 -1
- package/.claude/commands/flow/init.md +16 -1
- package/.claude/commands/flow/quality.md +5 -0
- package/.claude/commands/flow/release.md +33 -9
- package/.claude/commands/flow/restart.md +1 -1
- package/.claude/commands/flow/status.md +2 -2
- package/.claude/commands/flow/update.md +1 -1
- package/.claude/commands/flow/workspace.md +30 -4
- package/.claude/scripts/CLAUDE.md +79 -0
- package/.claude/scripts/create-requirement.sh +12 -0
- package/.claude/scripts/flow-quality-full.sh +32 -1
- package/.claude/scripts/flow-quality-quick.sh +57 -2
- package/.claude/scripts/flow-workspace-start.sh +135 -6
- package/.claude/scripts/flow-workspace-switch.sh +234 -0
- package/.claude/scripts/generate-status-report.sh +5 -5
- package/.claude/scripts/recover-workflow.sh +24 -24
- package/.claude/skills/workflow/flow-init/SKILL.md +8 -1
- package/.claude/skills/workflow/flow-quality/SKILL.md +4 -0
- package/.claude/skills/workflow/flow-release/SKILL.md +18 -5
- package/CHANGELOG.md +66 -0
- package/lib/compiler/__tests__/compile-regression.test.js +9 -0
- package/lib/compiler/__tests__/multi-module-emitters.test.js +37 -11
- package/lib/compiler/emitters/antigravity-emitter.js +22 -3
- package/lib/compiler/emitters/base-emitter.js +78 -0
- package/lib/compiler/emitters/codex-emitter.js +37 -34
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,72 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [4.1.4] - 2026-02-08
|
|
11
|
+
|
|
12
|
+
### 🧭 Workspace Worktree Session Recovery & Release Flow Clarity
|
|
13
|
+
|
|
14
|
+
v4.1.4 strengthens workspace-to-worktree continuity so developers can resume a requirement reliably across sessions, and clarifies flow init/release semantics in command and skill docs.
|
|
15
|
+
|
|
16
|
+
#### Added
|
|
17
|
+
|
|
18
|
+
- **Workspace switch script**
|
|
19
|
+
- Added `.claude/scripts/flow-workspace-switch.sh`
|
|
20
|
+
- Supports `REQ/BUG` pointer updates, journal logging, `--print-cd`, and sourced `--cd` switching
|
|
21
|
+
|
|
22
|
+
- **Scripts architecture map**
|
|
23
|
+
- Added `.claude/scripts/CLAUDE.md` as L2 directory map for script responsibilities
|
|
24
|
+
|
|
25
|
+
#### Changed
|
|
26
|
+
|
|
27
|
+
- **Workspace start behavior**
|
|
28
|
+
- `.claude/scripts/flow-workspace-start.sh` now accepts `REQ-XXX/BUG-XXX` override
|
|
29
|
+
- Added `--switch` and sourced `--cd` behavior for faster worktree handoff
|
|
30
|
+
- Added BUG status file compatibility (`devflow/bugs/*/status.json`)
|
|
31
|
+
|
|
32
|
+
- **Requirement initialization linkage**
|
|
33
|
+
- `.claude/scripts/create-requirement.sh` now syncs `devflow/workspace/{developer}/.current-req` when workspace exists
|
|
34
|
+
|
|
35
|
+
- **Flow docs and skills alignment**
|
|
36
|
+
- Updated flow init/release/workspace command docs and workflow skills to reflect:
|
|
37
|
+
- default worktree naming semantics
|
|
38
|
+
- merge semantics by release strategy
|
|
39
|
+
- workspace continuity expectations
|
|
40
|
+
|
|
41
|
+
#### Benefits
|
|
42
|
+
|
|
43
|
+
- ✅ New session recovery can target the intended REQ/BUG directly
|
|
44
|
+
- ✅ Worktree switching is faster and less error-prone via generated `cd` commands
|
|
45
|
+
- ✅ Flow release semantics are clearer when deciding between PR-only vs merge paths
|
|
46
|
+
|
|
47
|
+
## [4.1.3] - 2026-02-08
|
|
48
|
+
|
|
49
|
+
### 🔧 Flow Quality Default Path + AGENTS.md Safe Emit
|
|
50
|
+
|
|
51
|
+
v4.1.3 aligns release gates with `/flow-quality` as the default path and improves compiler emitters to preserve user-owned AGENTS memory content.
|
|
52
|
+
|
|
53
|
+
#### Fixed
|
|
54
|
+
|
|
55
|
+
- **Flow quality/release gate consistency**
|
|
56
|
+
- `/flow-quality` quick mode now generates minimal `TEST_REPORT.md` and `SECURITY_REPORT.md`
|
|
57
|
+
- Release entry gate accepts `quality_complete` (with `qa_complete` backward compatibility)
|
|
58
|
+
- Flow docs/scripts updated to recommend `/flow-quality` by default, with `--full` as enhanced review mode
|
|
59
|
+
|
|
60
|
+
- **AGENTS.md overwrite prevention in compiler emitters**
|
|
61
|
+
- Added managed block upsert mechanism in base emitter
|
|
62
|
+
- Codex/Antigravity emitters now write compact index blocks instead of appending full agent/rule bodies
|
|
63
|
+
- Existing user memory content in `AGENTS.md` is preserved
|
|
64
|
+
|
|
65
|
+
#### Added
|
|
66
|
+
|
|
67
|
+
- **Regression coverage for managed blocks**
|
|
68
|
+
- Tests for AGENTS managed block generation, idempotence, and preservation behavior
|
|
69
|
+
|
|
70
|
+
#### Benefits
|
|
71
|
+
|
|
72
|
+
- ✅ `flow-quality` becomes a true default path to `flow-release` without requiring `--full`
|
|
73
|
+
- ✅ Compiler output no longer clobbers user-maintained AGENTS memory sections
|
|
74
|
+
- ✅ Backward compatibility with legacy QA status remains intact
|
|
75
|
+
|
|
10
76
|
## [4.1.2] - 2026-02-07
|
|
11
77
|
|
|
12
78
|
### 🔧 Adapt Compiler Migration Reliability Fixes
|
|
@@ -74,6 +74,8 @@ describe('compile() regression', () => {
|
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
test('should compile nested commands and emit skills for codex', async () => {
|
|
77
|
+
fs.writeFileSync('AGENTS.md', '# User Memory\n\nKeep this content.\n');
|
|
78
|
+
|
|
77
79
|
const result = await compile({
|
|
78
80
|
sourceDir: '.claude/commands',
|
|
79
81
|
skillsDir: '.claude/skills',
|
|
@@ -90,5 +92,12 @@ describe('compile() regression', () => {
|
|
|
90
92
|
expect(fs.existsSync('.codex/skills/flow-dev/SKILL.md')).toBe(true);
|
|
91
93
|
expect(fs.existsSync('.codex/skills/orchestrator/SKILL.md')).toBe(true);
|
|
92
94
|
expect(fs.existsSync('AGENTS.md')).toBe(true);
|
|
95
|
+
|
|
96
|
+
const agentsContent = fs.readFileSync('AGENTS.md', 'utf8');
|
|
97
|
+
expect(agentsContent).toContain('# User Memory');
|
|
98
|
+
expect(agentsContent).toContain('<!-- cc-devflow:codex-agents:start -->');
|
|
99
|
+
expect(agentsContent).toContain('<!-- cc-devflow:codex-rules:start -->');
|
|
100
|
+
expect(agentsContent).not.toContain('# planner');
|
|
101
|
+
expect(agentsContent).not.toContain('# rule');
|
|
93
102
|
});
|
|
94
103
|
});
|
|
@@ -213,9 +213,10 @@ describe('CodexEmitter Multi-Module', () => {
|
|
|
213
213
|
expect(content).toContain('## Required Context');
|
|
214
214
|
});
|
|
215
215
|
|
|
216
|
-
test('emitAgents
|
|
216
|
+
test('emitAgents writes compact managed block and preserves existing content', async () => {
|
|
217
217
|
const sourceDir = path.join(tempDir, '.claude', 'agents');
|
|
218
218
|
const targetPath = path.join(tempDir, 'AGENTS.md');
|
|
219
|
+
fs.writeFileSync(targetPath, '# User Memory\n\nDo not overwrite this.\n');
|
|
219
220
|
|
|
220
221
|
const results = await emitter.emitAgents(sourceDir, targetPath);
|
|
221
222
|
|
|
@@ -223,25 +224,32 @@ describe('CodexEmitter Multi-Module', () => {
|
|
|
223
224
|
expect(fs.existsSync(targetPath)).toBe(true);
|
|
224
225
|
|
|
225
226
|
const content = fs.readFileSync(targetPath, 'utf8');
|
|
226
|
-
expect(content).toContain('#
|
|
227
|
-
expect(content).toContain('
|
|
227
|
+
expect(content).toContain('# User Memory');
|
|
228
|
+
expect(content).toContain('<!-- cc-devflow:codex-agents:start -->');
|
|
229
|
+
expect(content).toContain('## CC-DevFlow Agents');
|
|
230
|
+
expect(content).toContain('- Count: 1');
|
|
231
|
+
expect(content).not.toContain('This agent is for testing.');
|
|
228
232
|
});
|
|
229
233
|
|
|
230
|
-
test('emitRules
|
|
234
|
+
test('emitRules writes compact managed block and remains idempotent', async () => {
|
|
231
235
|
const sourceDir = path.join(tempDir, '.claude', 'rules');
|
|
232
236
|
const targetPath = path.join(tempDir, 'AGENTS.md');
|
|
233
237
|
|
|
234
|
-
|
|
235
|
-
fs.writeFileSync(targetPath, '# Agents\n\nExisting content.\n');
|
|
238
|
+
fs.writeFileSync(targetPath, '# User Memory\n\nKeep me.\n');
|
|
236
239
|
|
|
237
|
-
const
|
|
240
|
+
const first = await emitter.emitRules(sourceDir, targetPath);
|
|
241
|
+
const second = await emitter.emitRules(sourceDir, targetPath);
|
|
238
242
|
|
|
239
|
-
expect(
|
|
243
|
+
expect(first.length).toBe(1);
|
|
244
|
+
expect(second.length).toBe(1);
|
|
240
245
|
|
|
241
246
|
const content = fs.readFileSync(targetPath, 'utf8');
|
|
242
|
-
expect(content).toContain('#
|
|
243
|
-
expect(content).toContain('
|
|
244
|
-
expect(content).toContain('
|
|
247
|
+
expect(content).toContain('# User Memory');
|
|
248
|
+
expect(content).toContain('<!-- cc-devflow:codex-rules:start -->');
|
|
249
|
+
expect(content).toContain('## CC-DevFlow Rules');
|
|
250
|
+
expect(content).toContain('- Count: 1');
|
|
251
|
+
expect(content).not.toContain('This rule is for testing.');
|
|
252
|
+
expect(content.split('<!-- cc-devflow:codex-rules:start -->').length - 1).toBe(1);
|
|
245
253
|
});
|
|
246
254
|
});
|
|
247
255
|
|
|
@@ -428,6 +436,24 @@ describe('AntigravityEmitter Multi-Module', () => {
|
|
|
428
436
|
const targetPath = path.join(targetDir, 'test-rule.md');
|
|
429
437
|
expect(fs.existsSync(targetPath)).toBe(true);
|
|
430
438
|
});
|
|
439
|
+
|
|
440
|
+
test('emitAgents writes compact managed block and preserves existing content', async () => {
|
|
441
|
+
const sourceDir = path.join(tempDir, '.claude', 'agents');
|
|
442
|
+
const targetPath = path.join(tempDir, 'AGENTS.md');
|
|
443
|
+
fs.writeFileSync(targetPath, '# User Memory\n\nKeep this section.\n');
|
|
444
|
+
|
|
445
|
+
const results = await emitter.emitAgents(sourceDir, targetPath);
|
|
446
|
+
|
|
447
|
+
expect(results.length).toBe(1);
|
|
448
|
+
expect(fs.existsSync(targetPath)).toBe(true);
|
|
449
|
+
|
|
450
|
+
const content = fs.readFileSync(targetPath, 'utf8');
|
|
451
|
+
expect(content).toContain('# User Memory');
|
|
452
|
+
expect(content).toContain('<!-- cc-devflow:antigravity-agents:start -->');
|
|
453
|
+
expect(content).toContain('## CC-DevFlow Agents');
|
|
454
|
+
expect(content).toContain('- Count: 1');
|
|
455
|
+
expect(content).not.toContain('This agent is for testing.');
|
|
456
|
+
});
|
|
431
457
|
});
|
|
432
458
|
|
|
433
459
|
// ============================================================
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* 输出格式:
|
|
10
10
|
* - Commands: Markdown + YAML frontmatter -> .agent/workflows/
|
|
11
11
|
* - Skills: SKILL.md (YAML frontmatter) -> .agent/skills/
|
|
12
|
-
* - Agents:
|
|
12
|
+
* - Agents: 索引摘要写入 AGENTS.md(保留用户内容)
|
|
13
13
|
* - Rules: Markdown -> .agent/rules/
|
|
14
14
|
*
|
|
15
15
|
* 限制: 单文件 <= 12,000 字符,超限时自动拆分
|
|
@@ -319,10 +319,29 @@ class AntigravityEmitter extends BaseEmitter {
|
|
|
319
319
|
|
|
320
320
|
/**
|
|
321
321
|
* 编译 Agents 模块
|
|
322
|
-
* .claude/agents/[name].md -> AGENTS.md (
|
|
322
|
+
* .claude/agents/[name].md -> AGENTS.md (短索引,受管块)
|
|
323
323
|
*/
|
|
324
324
|
async emitAgents(sourceDir, targetPath) {
|
|
325
|
-
|
|
325
|
+
const results = [];
|
|
326
|
+
const agentNames = await this.readMarkdownEntryNames(sourceDir);
|
|
327
|
+
|
|
328
|
+
if (agentNames.length === 0) {
|
|
329
|
+
return results;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const summary = [
|
|
333
|
+
'## CC-DevFlow Agents',
|
|
334
|
+
'',
|
|
335
|
+
'- Scope: `.claude/agents/*.md`',
|
|
336
|
+
`- Count: ${agentNames.length}`,
|
|
337
|
+
`- Entries: ${this.formatCompactList(agentNames)}`,
|
|
338
|
+
'- Policy: Keep AGENTS.md concise; detailed agent instructions stay in source files.'
|
|
339
|
+
].join('\n');
|
|
340
|
+
|
|
341
|
+
const result = await this.upsertManagedBlock(targetPath, 'antigravity-agents', summary);
|
|
342
|
+
results.push({ ...result, count: agentNames.length });
|
|
343
|
+
|
|
344
|
+
return results;
|
|
326
345
|
}
|
|
327
346
|
|
|
328
347
|
/**
|
|
@@ -23,6 +23,7 @@ const crypto = require('crypto');
|
|
|
23
23
|
// SECURITY CONFIGURATION (FINDING-003)
|
|
24
24
|
// ============================================================
|
|
25
25
|
const MAX_OUTPUT_SIZE = 2 * 1024 * 1024; // 2MB limit
|
|
26
|
+
const MANAGED_BLOCK_PREFIX = 'cc-devflow';
|
|
26
27
|
|
|
27
28
|
// ============================================================
|
|
28
29
|
// MODULE_TYPES - 支持的模块类型
|
|
@@ -284,6 +285,83 @@ class BaseEmitter {
|
|
|
284
285
|
hashContent(content) {
|
|
285
286
|
return crypto.createHash('sha256').update(content).digest('hex');
|
|
286
287
|
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* 读取目录下的 Markdown 文件名(去掉 .md)
|
|
291
|
+
*/
|
|
292
|
+
async readMarkdownEntryNames(sourceDir) {
|
|
293
|
+
if (!fs.existsSync(sourceDir)) {
|
|
294
|
+
return [];
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const entries = await fs.promises.readdir(sourceDir, { withFileTypes: true });
|
|
298
|
+
|
|
299
|
+
return entries
|
|
300
|
+
.filter(entry => entry.isFile() && entry.name.endsWith('.md'))
|
|
301
|
+
.map(entry => entry.name.replace(/\.md$/, ''))
|
|
302
|
+
.sort((a, b) => a.localeCompare(b));
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* 格式化短列表,避免全局记忆文件过长
|
|
307
|
+
*/
|
|
308
|
+
formatCompactList(items, maxItems = 12) {
|
|
309
|
+
if (!items || items.length === 0) {
|
|
310
|
+
return '`(none)`';
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const visible = items.slice(0, maxItems).map(item => `\`${item}\``);
|
|
314
|
+
const hiddenCount = items.length - visible.length;
|
|
315
|
+
|
|
316
|
+
if (hiddenCount > 0) {
|
|
317
|
+
visible.push(`... (+${hiddenCount} more)`);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return visible.join(', ');
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* 受管块写入:仅替换指定区块,保留用户原有内容
|
|
325
|
+
*/
|
|
326
|
+
async upsertManagedBlock(targetPath, blockId, body) {
|
|
327
|
+
const startMarker = `<!-- ${MANAGED_BLOCK_PREFIX}:${blockId}:start -->`;
|
|
328
|
+
const endMarker = `<!-- ${MANAGED_BLOCK_PREFIX}:${blockId}:end -->`;
|
|
329
|
+
const managedBlock = `${startMarker}\n${body.trim()}\n${endMarker}`;
|
|
330
|
+
|
|
331
|
+
let existing = '';
|
|
332
|
+
if (fs.existsSync(targetPath)) {
|
|
333
|
+
existing = await fs.promises.readFile(targetPath, 'utf8');
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const merged = this._replaceManagedBlock(existing, startMarker, endMarker, managedBlock);
|
|
337
|
+
return this.emitToPath(targetPath, merged);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
_replaceManagedBlock(existing, startMarker, endMarker, managedBlock) {
|
|
341
|
+
const startIndex = existing.indexOf(startMarker);
|
|
342
|
+
const endIndex = existing.indexOf(endMarker);
|
|
343
|
+
|
|
344
|
+
if (startIndex !== -1 && endIndex !== -1 && endIndex > startIndex) {
|
|
345
|
+
const before = existing.slice(0, startIndex).trimEnd();
|
|
346
|
+
const after = existing.slice(endIndex + endMarker.length).trimStart();
|
|
347
|
+
|
|
348
|
+
return this._joinBlocks(before, managedBlock, after);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (!existing.trim()) {
|
|
352
|
+
return `${managedBlock}\n`;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return `${existing.trimEnd()}\n\n${managedBlock}\n`;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
_joinBlocks(...blocks) {
|
|
359
|
+
const validBlocks = blocks.filter(block => block && block.trim().length > 0);
|
|
360
|
+
if (validBlocks.length === 0) {
|
|
361
|
+
return '';
|
|
362
|
+
}
|
|
363
|
+
return `${validBlocks.join('\n\n')}\n`;
|
|
364
|
+
}
|
|
287
365
|
}
|
|
288
366
|
|
|
289
367
|
module.exports = BaseEmitter;
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
* 输出格式:
|
|
10
10
|
* - Commands: Markdown + YAML frontmatter → .codex/prompts/
|
|
11
11
|
* - Skills: SKILL.md (YAML frontmatter) → .codex/skills/
|
|
12
|
-
* - Agents:
|
|
13
|
-
* - Rules:
|
|
12
|
+
* - Agents: 索引摘要写入 AGENTS.md(保留用户内容)
|
|
13
|
+
* - Rules: 索引摘要写入 AGENTS.md(保留用户内容)
|
|
14
14
|
*
|
|
15
15
|
* v2.0: 支持多模块编译
|
|
16
16
|
*/
|
|
@@ -194,51 +194,54 @@ class CodexEmitter extends BaseEmitter {
|
|
|
194
194
|
|
|
195
195
|
/**
|
|
196
196
|
* 编译 Agents 模块
|
|
197
|
-
* .claude/agents/[name].md -> AGENTS.md (
|
|
197
|
+
* .claude/agents/[name].md -> AGENTS.md (短索引,受管块)
|
|
198
198
|
*/
|
|
199
199
|
async emitAgents(sourceDir, targetPath) {
|
|
200
|
-
|
|
200
|
+
const results = [];
|
|
201
|
+
const agentNames = await this.readMarkdownEntryNames(sourceDir);
|
|
202
|
+
|
|
203
|
+
if (agentNames.length === 0) {
|
|
204
|
+
return results;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const summary = [
|
|
208
|
+
'## CC-DevFlow Agents',
|
|
209
|
+
'',
|
|
210
|
+
'- Scope: `.claude/agents/*.md`',
|
|
211
|
+
`- Count: ${agentNames.length}`,
|
|
212
|
+
`- Entries: ${this.formatCompactList(agentNames)}`,
|
|
213
|
+
'- Policy: Keep AGENTS.md concise as global memory; full agent specs stay in source files.'
|
|
214
|
+
].join('\n');
|
|
215
|
+
|
|
216
|
+
const result = await this.upsertManagedBlock(targetPath, 'codex-agents', summary);
|
|
217
|
+
results.push({ ...result, count: agentNames.length });
|
|
218
|
+
|
|
219
|
+
return results;
|
|
201
220
|
}
|
|
202
221
|
|
|
203
222
|
/**
|
|
204
223
|
* 编译 Rules 模块
|
|
205
|
-
* .claude/rules/[name].md -> AGENTS.md (
|
|
224
|
+
* .claude/rules/[name].md -> AGENTS.md (短索引,受管块)
|
|
206
225
|
*/
|
|
207
226
|
async emitRules(sourceDir, targetPath) {
|
|
208
227
|
const results = [];
|
|
228
|
+
const ruleNames = await this.readMarkdownEntryNames(sourceDir);
|
|
209
229
|
|
|
210
|
-
if (
|
|
230
|
+
if (ruleNames.length === 0) {
|
|
211
231
|
return results;
|
|
212
232
|
}
|
|
213
233
|
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
sections.push(`### ${ruleName}\n\n${content}`);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
if (sections.length > 0) {
|
|
230
|
-
// 追加到现有 AGENTS.md
|
|
231
|
-
let existingContent = '';
|
|
232
|
-
if (fs.existsSync(targetPath)) {
|
|
233
|
-
existingContent = await fs.promises.readFile(targetPath, 'utf8');
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
const rulesSection = `\n\n## Rules\n\n${sections.join('\n\n---\n\n')}`;
|
|
237
|
-
const merged = existingContent + rulesSection;
|
|
238
|
-
|
|
239
|
-
const result = await this.emitToPath(targetPath, merged);
|
|
240
|
-
results.push(result);
|
|
241
|
-
}
|
|
234
|
+
const summary = [
|
|
235
|
+
'## CC-DevFlow Rules',
|
|
236
|
+
'',
|
|
237
|
+
'- Scope: `.claude/rules/*.md`',
|
|
238
|
+
`- Count: ${ruleNames.length}`,
|
|
239
|
+
`- Entries: ${this.formatCompactList(ruleNames)}`,
|
|
240
|
+
'- Policy: AGENTS.md stores only memory-level constraints, not full rule bodies.'
|
|
241
|
+
].join('\n');
|
|
242
|
+
|
|
243
|
+
const result = await this.upsertManagedBlock(targetPath, 'codex-rules', summary);
|
|
244
|
+
results.push({ ...result, count: ruleNames.length });
|
|
242
245
|
|
|
243
246
|
return results;
|
|
244
247
|
}
|