@hone-ai/cli 1.12.0 → 1.12.2

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 CHANGED
@@ -1035,6 +1035,11 @@ program
1035
1035
  docUrls,
1036
1036
  isRefresh,
1037
1037
  existingSkills,
1038
+ // HC-019z-followup-2: derive is always batch from the CLI —
1039
+ // there's no channel to relay user answers to the LLM mid-job.
1040
+ // The server's prompt Step 0c uses this to emit STEP_0C_SKIPPED
1041
+ // instead of stopping to ask, when no team docs are configured.
1042
+ interactive: false,
1038
1043
  });
1039
1044
  jobId = r.data.jobId;
1040
1045
  console.log(`Job queued: ${jobId}`);
@@ -1084,6 +1089,25 @@ program
1084
1089
  fs.writeFileSync(reportPath, result.changeReport || '');
1085
1090
  console.log(`\nChange report saved to: .github/skill-refresh-report.md`);
1086
1091
  } else {
1092
+ // HC-019z-followup-2: surface the non-interactive skip notice if
1093
+ // the prompt emitted STEP_0C_SKIPPED. The marker appears in the
1094
+ // server's rawOutputTail when the LLM honored the non-interactive
1095
+ // guard. Without this message, the user is mystified by an empty
1096
+ // skill set.
1097
+ const rawOutput = result.rawOutputTail || result.rawOutput || '';
1098
+ if (rawOutput.includes('STEP_0C_SKIPPED')) {
1099
+ console.log('');
1100
+ console.log('⚠ Phase 0c (team documentation URLs) skipped — derive is non-interactive.');
1101
+ console.log(' To include team docs (Confluence, wiki, runbooks, etc.) in derivation,');
1102
+ console.log(' add them to .github/.pipeline-config.yml under documentation.external_urls:');
1103
+ console.log(' documentation:');
1104
+ console.log(' external_urls:');
1105
+ console.log(' - https://yourwiki.example/architecture');
1106
+ console.log(' - https://yourwiki.example/conventions');
1107
+ console.log(' Then re-run `hone derive`. (HC-019z-followup-2)');
1108
+ console.log('');
1109
+ }
1110
+
1087
1111
  // Write generated skills to disk
1088
1112
  console.log('Writing generated skills...');
1089
1113
  if (result.skills) {
@@ -2610,49 +2634,13 @@ function sleep(ms) {
2610
2634
  return new Promise(resolve => setTimeout(resolve, ms));
2611
2635
  }
2612
2636
 
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;
2637
+ // HC-019y-followup-1: splice helper extracted to cli/lib/ so tests
2638
+ // can require it without dragging in the commander entry point.
2639
+ // (Previous attempt to gate `program.parse` behind `require.main ===
2640
+ // module` broke the CLI in 1.12.0 because bin/hone.js does
2641
+ // `require('../hone-cli.js')` making require.main the bin wrapper,
2642
+ // not hone-cli.js, so the gate never fired and parse never ran.)
2643
+ const { splicePreserveRepoSpecific } = require('./lib/splice-repo-specific');
2656
2644
 
2657
2645
  // ── STATUS command (H-009) ────────────────────────────────────────────────────
2658
2646
  // Show pipeline state for a story (or use --all for every in-flight story).
@@ -5295,9 +5283,4 @@ program
5295
5283
  .description('Hone AI — Enterprise SDLC Pipeline CLI')
5296
5284
  .version(pkg.version);
5297
5285
 
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
- }
5286
+ program.parse(process.argv);
@@ -0,0 +1,61 @@
1
+ 'use strict';
2
+ /**
3
+ * HC-019y-followup-1: when `hone derive` writes a SKILL.md, splice the
4
+ * existing adopter REPO-SPECIFIC content over whatever the LLM produced
5
+ * for that section. The semantic guarantee: adopter-curated content
6
+ * (everything below the `<!-- REPO-SPECIFIC -->` marker) is NEVER lost
7
+ * across derive runs.
8
+ *
9
+ * Pre-fix: derive wrote the file blind (fs.writeFileSync(skillFile,
10
+ * content)). 5 OptionsFlow regression tests broke after a single derive
11
+ * because 378 lines of E33-A/E34-B-added content disappeared.
12
+ *
13
+ * Extracted to its own file (cli/lib/) so it can be require()'d by
14
+ * tests without dragging in cli/hone-cli.js's commander entry point.
15
+ * The earlier attempt to gate `program.parse` behind
16
+ * `require.main === module` broke the CLI in production because
17
+ * bin/hone.js calls `require('../hone-cli.js')` — making require.main
18
+ * the bin/hone.js wrapper, not hone-cli.js itself, so the gate never
19
+ * fired and `program.parse` never ran. Lesson: don't gate side-effect
20
+ * top-level code; extract testable helpers to their own modules.
21
+ */
22
+ const fs = require('node:fs');
23
+
24
+ /**
25
+ * Splice adopter REPO-SPECIFIC tail into derive output.
26
+ *
27
+ * @param {string} existingPath absolute path of the file being overwritten
28
+ * @param {string} newContent the content from `hone derive` server response
29
+ * @returns {{ merged: string, preserved: boolean }}
30
+ * merged: bytes to write
31
+ * preserved: true if adopter REPO-SPECIFIC content was preserved
32
+ * across the splice; false for fresh writes
33
+ */
34
+ function splicePreserveRepoSpecific(existingPath, newContent) {
35
+ const MARKER = '<!-- REPO-SPECIFIC';
36
+ if (!fs.existsSync(existingPath)) {
37
+ // Fresh adopter — no existing file. Write new content as-is.
38
+ return { merged: newContent, preserved: false };
39
+ }
40
+ const existing = fs.readFileSync(existingPath, 'utf8');
41
+ const oldIdx = existing.indexOf(MARKER);
42
+ if (oldIdx < 0) {
43
+ // Existing file has no REPO-SPECIFIC marker (likely a non-skill or
44
+ // legacy file). Nothing to preserve.
45
+ return { merged: newContent, preserved: false };
46
+ }
47
+ const newIdx = newContent.indexOf(MARKER);
48
+ if (newIdx < 0) {
49
+ // New content has no REPO-SPECIFIC section. Append the existing one.
50
+ return { merged: newContent.trimEnd() + '\n\n' + existing.slice(oldIdx), preserved: true };
51
+ }
52
+ // Both have REPO-SPECIFIC. Take new content up to the marker, then
53
+ // append everything from existing's marker to EOF. This preserves
54
+ // adopter-curated content while updating the body before the marker.
55
+ return {
56
+ merged: newContent.slice(0, newIdx) + existing.slice(oldIdx),
57
+ preserved: true,
58
+ };
59
+ }
60
+
61
+ module.exports = { splicePreserveRepoSpecific };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hone-ai/cli",
3
- "version": "1.12.0",
3
+ "version": "1.12.2",
4
4
  "description": "Hone AI — Enterprise SDLC Pipeline CLI",
5
5
  "main": "hone-cli.js",
6
6
  "bin": {