@hone-ai/cli 1.11.0 → 1.12.0
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/hone-cli.js +63 -3
- package/package.json +1 -1
package/hone-cli.js
CHANGED
|
@@ -1087,13 +1087,24 @@ program
|
|
|
1087
1087
|
// Write generated skills to disk
|
|
1088
1088
|
console.log('Writing generated skills...');
|
|
1089
1089
|
if (result.skills) {
|
|
1090
|
+
let preservedCount = 0;
|
|
1090
1091
|
for (const [skillName, content] of Object.entries(result.skills)) {
|
|
1091
1092
|
if (!content || content.length < 50) continue;
|
|
1092
1093
|
const skillDir = path.join(repoRoot, '.github', 'skills', skillName);
|
|
1093
1094
|
const skillFile = path.join(skillDir, 'SKILL.md');
|
|
1094
1095
|
fs.mkdirSync(skillDir, { recursive: true });
|
|
1095
|
-
|
|
1096
|
-
|
|
1096
|
+
const { merged, preserved } = splicePreserveRepoSpecific(skillFile, content);
|
|
1097
|
+
fs.writeFileSync(skillFile, merged);
|
|
1098
|
+
if (preserved) {
|
|
1099
|
+
preservedCount++;
|
|
1100
|
+
console.log(` ✓ .github/skills/${skillName}/SKILL.md (preserved adopter REPO-SPECIFIC content)`);
|
|
1101
|
+
} else {
|
|
1102
|
+
console.log(` ✓ .github/skills/${skillName}/SKILL.md`);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
if (preservedCount > 0) {
|
|
1106
|
+
console.log(`\n Preserved adopter REPO-SPECIFIC content in ${preservedCount} skill(s).`);
|
|
1107
|
+
console.log(` (HC-019y-followup-1: derive no longer overwrites curated REPO-SPECIFIC sections)`);
|
|
1097
1108
|
}
|
|
1098
1109
|
}
|
|
1099
1110
|
|
|
@@ -2599,6 +2610,50 @@ function sleep(ms) {
|
|
|
2599
2610
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
2600
2611
|
}
|
|
2601
2612
|
|
|
2613
|
+
/**
|
|
2614
|
+
* HC-019y-followup-1: when `hone derive` writes a SKILL.md, splice the
|
|
2615
|
+
* existing adopter REPO-SPECIFIC content over whatever the LLM produced
|
|
2616
|
+
* for that section. The semantic guarantee: adopter-curated content
|
|
2617
|
+
* (everything below the `<!-- REPO-SPECIFIC -->` marker) is NEVER lost
|
|
2618
|
+
* across derive runs.
|
|
2619
|
+
*
|
|
2620
|
+
* Pre-fix: derive wrote the file blind (fs.writeFileSync(skillFile,
|
|
2621
|
+
* content)). 5 OptionsFlow regression tests broke after a single derive
|
|
2622
|
+
* because 378 lines of E33-A/E34-B-added content disappeared.
|
|
2623
|
+
*
|
|
2624
|
+
* Returns { merged, preserved }:
|
|
2625
|
+
* - merged: the bytes to write (always a string)
|
|
2626
|
+
* - preserved: true if adopter REPO-SPECIFIC content was preserved
|
|
2627
|
+
* across the splice; false for fresh writes
|
|
2628
|
+
*/
|
|
2629
|
+
function splicePreserveRepoSpecific(existingPath, newContent) {
|
|
2630
|
+
const MARKER = '<!-- REPO-SPECIFIC';
|
|
2631
|
+
if (!fs.existsSync(existingPath)) {
|
|
2632
|
+
// Fresh adopter — no existing file. Write new content as-is.
|
|
2633
|
+
return { merged: newContent, preserved: false };
|
|
2634
|
+
}
|
|
2635
|
+
const existing = fs.readFileSync(existingPath, 'utf8');
|
|
2636
|
+
const oldIdx = existing.indexOf(MARKER);
|
|
2637
|
+
if (oldIdx < 0) {
|
|
2638
|
+
// Existing file has no REPO-SPECIFIC marker (likely a non-skill or
|
|
2639
|
+
// legacy file). Nothing to preserve.
|
|
2640
|
+
return { merged: newContent, preserved: false };
|
|
2641
|
+
}
|
|
2642
|
+
const newIdx = newContent.indexOf(MARKER);
|
|
2643
|
+
if (newIdx < 0) {
|
|
2644
|
+
// New content has no REPO-SPECIFIC section. Append the existing one.
|
|
2645
|
+
return { merged: newContent.trimEnd() + '\n\n' + existing.slice(oldIdx), preserved: true };
|
|
2646
|
+
}
|
|
2647
|
+
// Both have REPO-SPECIFIC. Take new content up to the marker, then
|
|
2648
|
+
// append everything from existing's marker to EOF. This preserves
|
|
2649
|
+
// adopter-curated content while updating the body before the marker.
|
|
2650
|
+
return {
|
|
2651
|
+
merged: newContent.slice(0, newIdx) + existing.slice(oldIdx),
|
|
2652
|
+
preserved: true,
|
|
2653
|
+
};
|
|
2654
|
+
}
|
|
2655
|
+
module.exports.splicePreserveRepoSpecific = splicePreserveRepoSpecific;
|
|
2656
|
+
|
|
2602
2657
|
// ── STATUS command (H-009) ────────────────────────────────────────────────────
|
|
2603
2658
|
// Show pipeline state for a story (or use --all for every in-flight story).
|
|
2604
2659
|
// Reads .github/pipeline/<STORY-ID>/metadata.yml + filesystem; uses
|
|
@@ -5240,4 +5295,9 @@ program
|
|
|
5240
5295
|
.description('Hone AI — Enterprise SDLC Pipeline CLI')
|
|
5241
5296
|
.version(pkg.version);
|
|
5242
5297
|
|
|
5243
|
-
|
|
5298
|
+
// HC-019y-followup-1: gate commander invocation so the file can be
|
|
5299
|
+
// require()'d by tests for helpers like splicePreserveRepoSpecific
|
|
5300
|
+
// without auto-running the CLI's --help.
|
|
5301
|
+
if (require.main === module) {
|
|
5302
|
+
program.parse(process.argv);
|
|
5303
|
+
}
|