agileflow 2.94.1 → 2.95.1

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 (74) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +3 -3
  3. package/lib/colors.generated.js +117 -0
  4. package/lib/colors.js +59 -109
  5. package/lib/generator-factory.js +333 -0
  6. package/lib/path-utils.js +49 -0
  7. package/lib/session-registry.js +25 -15
  8. package/lib/smart-json-file.js +40 -32
  9. package/lib/state-machine.js +286 -0
  10. package/package.json +1 -1
  11. package/scripts/agileflow-configure.js +7 -6
  12. package/scripts/archive-completed-stories.sh +86 -11
  13. package/scripts/babysit-context-restore.js +89 -0
  14. package/scripts/claude-tmux.sh +111 -5
  15. package/scripts/damage-control/bash-tool-damage-control.js +11 -247
  16. package/scripts/damage-control/edit-tool-damage-control.js +9 -249
  17. package/scripts/damage-control/write-tool-damage-control.js +9 -244
  18. package/scripts/generate-colors.js +314 -0
  19. package/scripts/lib/colors.generated.sh +82 -0
  20. package/scripts/lib/colors.sh +10 -70
  21. package/scripts/lib/configure-features.js +401 -0
  22. package/scripts/lib/context-loader.js +181 -52
  23. package/scripts/precompact-context.sh +54 -17
  24. package/scripts/session-coordinator.sh +2 -2
  25. package/scripts/session-manager.js +653 -10
  26. package/src/core/commands/audit.md +93 -0
  27. package/src/core/commands/auto.md +73 -0
  28. package/src/core/commands/babysit.md +169 -13
  29. package/src/core/commands/baseline.md +73 -0
  30. package/src/core/commands/batch.md +64 -0
  31. package/src/core/commands/blockers.md +60 -0
  32. package/src/core/commands/board.md +66 -0
  33. package/src/core/commands/choose.md +77 -0
  34. package/src/core/commands/ci.md +77 -0
  35. package/src/core/commands/compress.md +27 -1
  36. package/src/core/commands/configure.md +126 -10
  37. package/src/core/commands/council.md +74 -0
  38. package/src/core/commands/debt.md +72 -0
  39. package/src/core/commands/deploy.md +73 -0
  40. package/src/core/commands/deps.md +68 -0
  41. package/src/core/commands/docs.md +60 -0
  42. package/src/core/commands/feedback.md +68 -0
  43. package/src/core/commands/ideate.md +74 -0
  44. package/src/core/commands/impact.md +74 -0
  45. package/src/core/commands/install.md +529 -0
  46. package/src/core/commands/maintain.md +558 -0
  47. package/src/core/commands/metrics.md +75 -0
  48. package/src/core/commands/multi-expert.md +74 -0
  49. package/src/core/commands/packages.md +69 -0
  50. package/src/core/commands/readme-sync.md +64 -0
  51. package/src/core/commands/research/analyze.md +285 -121
  52. package/src/core/commands/research/import.md +281 -109
  53. package/src/core/commands/retro.md +76 -0
  54. package/src/core/commands/review.md +72 -0
  55. package/src/core/commands/rlm.md +83 -0
  56. package/src/core/commands/rpi.md +90 -0
  57. package/src/core/commands/session/cleanup.md +214 -12
  58. package/src/core/commands/session/end.md +155 -17
  59. package/src/core/commands/sprint.md +72 -0
  60. package/src/core/commands/story-validate.md +68 -0
  61. package/src/core/commands/template.md +69 -0
  62. package/src/core/commands/tests.md +83 -0
  63. package/src/core/commands/update.md +59 -0
  64. package/src/core/commands/validate-expertise.md +76 -0
  65. package/src/core/commands/velocity.md +74 -0
  66. package/src/core/commands/verify.md +91 -0
  67. package/src/core/commands/whats-new.md +69 -0
  68. package/src/core/commands/workflow.md +88 -0
  69. package/src/core/templates/command-documentation.md +187 -0
  70. package/tools/cli/commands/session.js +1171 -0
  71. package/tools/cli/commands/setup.js +2 -81
  72. package/tools/cli/installers/core/installer.js +0 -5
  73. package/tools/cli/installers/ide/claude-code.js +6 -0
  74. package/tools/cli/lib/config-manager.js +42 -5
@@ -6,6 +6,7 @@
6
6
 
7
7
  const fs = require('fs');
8
8
  const path = require('path');
9
+ const os = require('os');
9
10
  const {
10
11
  c,
11
12
  log,
@@ -39,6 +40,14 @@ const FEATURES = {
39
40
  },
40
41
  askuserquestion: { metadataOnly: true },
41
42
  tmuxautospawn: { metadataOnly: true },
43
+ shellaliases: {
44
+ metadataOnly: false,
45
+ description: 'Shell aliases (af/agileflow) for tmux-wrapped Claude',
46
+ },
47
+ claudemdreinforcement: {
48
+ metadataOnly: false,
49
+ description: 'Add /babysit rules to CLAUDE.md for context preservation',
50
+ },
42
51
  };
43
52
 
44
53
  const PROFILES = {
@@ -88,6 +97,26 @@ const PROFILES = {
88
97
  'tmuxautospawn',
89
98
  ],
90
99
  },
100
+ experimental: {
101
+ description:
102
+ '⚠️ CONTEXT HEAVY: Full command file injection during compact (uses more tokens but may be more reliable)',
103
+ enable: [
104
+ 'sessionstart',
105
+ 'precompact',
106
+ 'archival',
107
+ 'statusline',
108
+ 'ralphloop',
109
+ 'selfimprove',
110
+ 'askuserquestion',
111
+ 'tmuxautospawn',
112
+ ],
113
+ archivalDays: 30,
114
+ experimental: {
115
+ fullFileInjection: true,
116
+ description:
117
+ 'Instead of compact summaries, injects entire command files during context compaction',
118
+ },
119
+ },
91
120
  };
92
121
 
93
122
  const STATUSLINE_COMPONENTS = [
@@ -243,6 +272,68 @@ function enableFeature(feature, options = {}, version) {
243
272
  return true;
244
273
  }
245
274
 
275
+ // Handle shell aliases
276
+ if (feature === 'shellaliases') {
277
+ const result = enableShellAliases();
278
+ if (
279
+ result.configured.length > 0 ||
280
+ result.skipped.some(s => s.includes('already configured'))
281
+ ) {
282
+ updateMetadata(
283
+ {
284
+ features: {
285
+ shellAliases: {
286
+ enabled: true,
287
+ version,
288
+ at: new Date().toISOString(),
289
+ shells: result.configured,
290
+ },
291
+ },
292
+ },
293
+ version
294
+ );
295
+ if (result.configured.length > 0) {
296
+ success(`Shell aliases added to: ${result.configured.join(', ')}`);
297
+ info('Reload shell: source ~/.bashrc or source ~/.zshrc');
298
+ info('Then use "af" or "agileflow" to start Claude in tmux');
299
+ } else {
300
+ info('Shell aliases already configured');
301
+ }
302
+ return true;
303
+ }
304
+ if (result.skipped.length > 0) {
305
+ warn(`Shell aliases skipped: ${result.skipped.join(', ')}`);
306
+ }
307
+ return false;
308
+ }
309
+
310
+ // Handle CLAUDE.md reinforcement
311
+ if (feature === 'claudemdreinforcement') {
312
+ const result = enableClaudeMdReinforcement();
313
+ if (result.success) {
314
+ updateMetadata(
315
+ {
316
+ features: {
317
+ claudeMdReinforcement: {
318
+ enabled: true,
319
+ version,
320
+ at: new Date().toISOString(),
321
+ },
322
+ },
323
+ },
324
+ version
325
+ );
326
+ if (result.added) {
327
+ success('Added /babysit rules to CLAUDE.md');
328
+ } else {
329
+ info('CLAUDE.md already has /babysit rules');
330
+ }
331
+ return true;
332
+ }
333
+ error(`Failed to update CLAUDE.md: ${result.error}`);
334
+ return false;
335
+ }
336
+
246
337
  // Handle damage control
247
338
  if (feature === 'damagecontrol') {
248
339
  return enableDamageControl(settings, options, version);
@@ -547,6 +638,53 @@ function disableFeature(feature, version) {
547
638
  return true;
548
639
  }
549
640
 
641
+ // Disable shell aliases
642
+ if (feature === 'shellaliases') {
643
+ const result = disableShellAliases();
644
+ updateMetadata(
645
+ {
646
+ features: {
647
+ shellAliases: {
648
+ enabled: false,
649
+ version,
650
+ at: new Date().toISOString(),
651
+ },
652
+ },
653
+ },
654
+ version
655
+ );
656
+ if (result.removed.length > 0) {
657
+ success(`Shell aliases removed from: ${result.removed.join(', ')}`);
658
+ info('Reload shell: source ~/.bashrc or source ~/.zshrc');
659
+ } else {
660
+ info('No shell aliases found to remove');
661
+ }
662
+ return true;
663
+ }
664
+
665
+ // Disable CLAUDE.md reinforcement
666
+ if (feature === 'claudemdreinforcement') {
667
+ const result = disableClaudeMdReinforcement();
668
+ updateMetadata(
669
+ {
670
+ features: {
671
+ claudeMdReinforcement: {
672
+ enabled: false,
673
+ version,
674
+ at: new Date().toISOString(),
675
+ },
676
+ },
677
+ },
678
+ version
679
+ );
680
+ if (result.removed) {
681
+ success('Removed /babysit rules from CLAUDE.md');
682
+ } else {
683
+ info('CLAUDE.md did not have /babysit rules');
684
+ }
685
+ return true;
686
+ }
687
+
550
688
  // Disable damage control
551
689
  if (feature === 'damagecontrol') {
552
690
  if (settings.hooks?.PreToolUse && Array.isArray(settings.hooks.PreToolUse)) {
@@ -625,6 +763,43 @@ function applyProfile(profileName, options = {}, version) {
625
763
  profile.disable.forEach(f => disableFeature(f, version));
626
764
  }
627
765
 
766
+ // Handle experimental profile settings
767
+ if (profile.experimental) {
768
+ updateMetadata(
769
+ {
770
+ features: {
771
+ experimental: {
772
+ enabled: true,
773
+ fullFileInjection: profile.experimental.fullFileInjection || false,
774
+ version,
775
+ at: new Date().toISOString(),
776
+ },
777
+ },
778
+ },
779
+ version
780
+ );
781
+ if (profile.experimental.fullFileInjection) {
782
+ warn('⚠️ EXPERIMENTAL: Full file injection enabled');
783
+ info(' PreCompact will inject entire command files instead of compact summaries');
784
+ info(' This uses more context tokens but may provide better instruction adherence');
785
+ }
786
+ } else {
787
+ // Disable experimental mode if switching to non-experimental profile
788
+ updateMetadata(
789
+ {
790
+ features: {
791
+ experimental: {
792
+ enabled: false,
793
+ fullFileInjection: false,
794
+ version,
795
+ at: new Date().toISOString(),
796
+ },
797
+ },
798
+ },
799
+ version
800
+ );
801
+ }
802
+
628
803
  return true;
629
804
  }
630
805
 
@@ -837,6 +1012,226 @@ function upgradeFeatures(status, version) {
837
1012
  return upgraded > 0;
838
1013
  }
839
1014
 
1015
+ // ============================================================================
1016
+ // SHELL ALIASES
1017
+ // ============================================================================
1018
+
1019
+ const SHELL_ALIAS_MARKER = '# AgileFlow tmux wrapper';
1020
+ const SHELL_ALIAS_BLOCK = `
1021
+ ${SHELL_ALIAS_MARKER}
1022
+ # Use 'af' or 'agileflow' for tmux, 'claude' stays normal
1023
+ alias af="bash .agileflow/scripts/af"
1024
+ alias agileflow="bash .agileflow/scripts/af"
1025
+ `;
1026
+
1027
+ /**
1028
+ * Enable shell aliases by adding them to ~/.bashrc and ~/.zshrc
1029
+ * @returns {object} Result with configured and skipped shells
1030
+ */
1031
+ function enableShellAliases() {
1032
+ const result = {
1033
+ configured: [],
1034
+ skipped: [],
1035
+ error: null,
1036
+ };
1037
+
1038
+ // Only set up aliases on Unix-like systems
1039
+ if (process.platform === 'win32') {
1040
+ result.skipped.push('Windows (not supported)');
1041
+ return result;
1042
+ }
1043
+
1044
+ const homeDir = os.homedir();
1045
+ const rcFiles = [
1046
+ { name: 'bash', path: path.join(homeDir, '.bashrc') },
1047
+ { name: 'zsh', path: path.join(homeDir, '.zshrc') },
1048
+ ];
1049
+
1050
+ for (const rc of rcFiles) {
1051
+ try {
1052
+ // Check if RC file exists
1053
+ if (!fs.existsSync(rc.path)) {
1054
+ result.skipped.push(`${rc.name} (no ${path.basename(rc.path)})`);
1055
+ continue;
1056
+ }
1057
+
1058
+ const content = fs.readFileSync(rc.path, 'utf8');
1059
+
1060
+ // Check if aliases already exist
1061
+ if (content.includes(SHELL_ALIAS_MARKER)) {
1062
+ result.skipped.push(`${rc.name} (already configured)`);
1063
+ continue;
1064
+ }
1065
+
1066
+ // Append aliases to RC file
1067
+ fs.appendFileSync(rc.path, SHELL_ALIAS_BLOCK);
1068
+ result.configured.push(rc.name);
1069
+ } catch (err) {
1070
+ result.skipped.push(`${rc.name} (error: ${err.message})`);
1071
+ }
1072
+ }
1073
+
1074
+ return result;
1075
+ }
1076
+
1077
+ /**
1078
+ * Disable shell aliases by removing them from ~/.bashrc and ~/.zshrc
1079
+ * @returns {object} Result with removed shells
1080
+ */
1081
+ function disableShellAliases() {
1082
+ const result = {
1083
+ removed: [],
1084
+ skipped: [],
1085
+ };
1086
+
1087
+ if (process.platform === 'win32') {
1088
+ return result;
1089
+ }
1090
+
1091
+ const homeDir = os.homedir();
1092
+ const rcFiles = [
1093
+ { name: 'bash', path: path.join(homeDir, '.bashrc') },
1094
+ { name: 'zsh', path: path.join(homeDir, '.zshrc') },
1095
+ ];
1096
+
1097
+ for (const rc of rcFiles) {
1098
+ try {
1099
+ if (!fs.existsSync(rc.path)) {
1100
+ continue;
1101
+ }
1102
+
1103
+ const content = fs.readFileSync(rc.path, 'utf8');
1104
+
1105
+ if (!content.includes(SHELL_ALIAS_MARKER)) {
1106
+ continue;
1107
+ }
1108
+
1109
+ // Remove the alias block
1110
+ const lines = content.split('\n');
1111
+ const filteredLines = [];
1112
+ let inBlock = false;
1113
+
1114
+ for (const line of lines) {
1115
+ if (line.includes(SHELL_ALIAS_MARKER)) {
1116
+ inBlock = true;
1117
+ continue;
1118
+ }
1119
+ if (
1120
+ inBlock &&
1121
+ (line.startsWith('# Use ') ||
1122
+ line.startsWith('alias af=') ||
1123
+ line.startsWith('alias agileflow='))
1124
+ ) {
1125
+ continue;
1126
+ }
1127
+ if (inBlock && line.trim() === '') {
1128
+ inBlock = false;
1129
+ continue;
1130
+ }
1131
+ inBlock = false;
1132
+ filteredLines.push(line);
1133
+ }
1134
+
1135
+ fs.writeFileSync(rc.path, filteredLines.join('\n'), 'utf8');
1136
+ result.removed.push(rc.name);
1137
+ } catch (err) {
1138
+ result.skipped.push(`${rc.name} (error: ${err.message})`);
1139
+ }
1140
+ }
1141
+
1142
+ return result;
1143
+ }
1144
+
1145
+ // ============================================================================
1146
+ // CLAUDE.MD REINFORCEMENT
1147
+ // ============================================================================
1148
+
1149
+ const CLAUDE_MD_MARKER = '<!-- AGILEFLOW_BABYSIT_RULES -->';
1150
+ const CLAUDE_MD_CONTENT = `
1151
+
1152
+ ${CLAUDE_MD_MARKER}
1153
+ ## AgileFlow /babysit Context Preservation Rules
1154
+
1155
+ When \`/agileflow:babysit\` is active (check session-state.json), these rules are MANDATORY:
1156
+
1157
+ 1. **ALWAYS end responses with the AskUserQuestion tool** - Not text like "What next?" but the ACTUAL TOOL CALL
1158
+ 2. **Use Plan Mode for non-trivial tasks** - Call \`EnterPlanMode\` before complex implementations
1159
+ 3. **Delegate complex work to domain experts** - Use \`Task\` tool with appropriate \`subagent_type\`
1160
+ 4. **Track progress with TodoWrite** - For any task with 3+ steps
1161
+
1162
+ These rules persist across conversation compaction. Check \`docs/09-agents/session-state.json\` for active commands.
1163
+ ${CLAUDE_MD_MARKER}
1164
+ `;
1165
+
1166
+ /**
1167
+ * Enable CLAUDE.md reinforcement by adding babysit rules
1168
+ * @returns {object} Result with success, added, and error
1169
+ */
1170
+ function enableClaudeMdReinforcement() {
1171
+ const claudeMdPath = path.join(process.cwd(), 'CLAUDE.md');
1172
+
1173
+ try {
1174
+ let existingContent = '';
1175
+ if (fs.existsSync(claudeMdPath)) {
1176
+ existingContent = fs.readFileSync(claudeMdPath, 'utf8');
1177
+ }
1178
+
1179
+ // Only append if marker doesn't exist
1180
+ if (existingContent.includes(CLAUDE_MD_MARKER)) {
1181
+ return { success: true, added: false };
1182
+ }
1183
+
1184
+ fs.appendFileSync(claudeMdPath, CLAUDE_MD_CONTENT);
1185
+ return { success: true, added: true };
1186
+ } catch (err) {
1187
+ return { success: false, error: err.message };
1188
+ }
1189
+ }
1190
+
1191
+ /**
1192
+ * Disable CLAUDE.md reinforcement by removing babysit rules
1193
+ * @returns {object} Result with removed flag
1194
+ */
1195
+ function disableClaudeMdReinforcement() {
1196
+ const claudeMdPath = path.join(process.cwd(), 'CLAUDE.md');
1197
+
1198
+ if (!fs.existsSync(claudeMdPath)) {
1199
+ return { removed: false };
1200
+ }
1201
+
1202
+ try {
1203
+ const content = fs.readFileSync(claudeMdPath, 'utf8');
1204
+
1205
+ if (!content.includes(CLAUDE_MD_MARKER)) {
1206
+ return { removed: false };
1207
+ }
1208
+
1209
+ // Remove the section between markers (inclusive)
1210
+ const startIdx = content.indexOf(CLAUDE_MD_MARKER);
1211
+ const endMarkerIdx = content.indexOf(CLAUDE_MD_MARKER, startIdx + CLAUDE_MD_MARKER.length);
1212
+
1213
+ if (startIdx === -1 || endMarkerIdx === -1) {
1214
+ return { removed: false };
1215
+ }
1216
+
1217
+ // Find the start of the line containing the first marker
1218
+ let lineStart = content.lastIndexOf('\n', startIdx);
1219
+ if (lineStart === -1) lineStart = 0;
1220
+
1221
+ // Find the end of the line containing the second marker
1222
+ let lineEnd = content.indexOf('\n', endMarkerIdx + CLAUDE_MD_MARKER.length);
1223
+ if (lineEnd === -1) lineEnd = content.length;
1224
+
1225
+ const newContent = content.slice(0, lineStart) + content.slice(lineEnd);
1226
+
1227
+ // Clean up any trailing newlines
1228
+ fs.writeFileSync(claudeMdPath, newContent.trimEnd() + '\n', 'utf8');
1229
+ return { removed: true };
1230
+ } catch (err) {
1231
+ return { removed: false, error: err.message };
1232
+ }
1233
+ }
1234
+
840
1235
  module.exports = {
841
1236
  // Constants
842
1237
  FEATURES,
@@ -856,4 +1251,10 @@ module.exports = {
856
1251
  // Helpers
857
1252
  scriptExists,
858
1253
  getScriptPath,
1254
+ // Shell aliases
1255
+ enableShellAliases,
1256
+ disableShellAliases,
1257
+ // CLAUDE.md reinforcement
1258
+ enableClaudeMdReinforcement,
1259
+ disableClaudeMdReinforcement,
859
1260
  };