claude-flow 3.59.10 → 3.59.12

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "adoptedAt": 1792606218653,
2
+ "adoptedAt": 1792615534268,
3
3
  "championId": "sha256:6141a8ea990c5063b77e090ae8f37f9c539d8aa8f58dcceb30f3a82f97e57319",
4
4
  "manifest": {
5
5
  "schema": "ruflo.proven-config/v1",
@@ -19,10 +19,21 @@ This skill provides professional pair programming capabilities with AI assistanc
19
19
  - **Code Review**: Security scanning, performance analysis, best practice enforcement
20
20
  - **Session Persistence**: Auto-save, recovery, export, and sharing
21
21
 
22
+ ## How Claude Code Uses This
23
+
24
+ The CLI holds the session state; Claude Code reads it. There is no REPL to type into.
25
+
26
+ 1. At the start of every turn run `ruflo pair status --json`. If `active` is `false`, this skill is dormant.
27
+ 2. Follow `mode` and `aiRole`. As **driver** you write the code and the human reviews. As **navigator** you review and suggest and never edit unless asked. `tdd`, `review`, `mentor` and `debug` refine that behaviour as described below.
28
+ 3. When `switchDue` is `true`, run `ruflo pair switch`, announce the swap, and continue in the new role.
29
+ 4. Change mode mid-session with `ruflo pair mode <mode>`. The human can run the same commands from their shell.
30
+
31
+ State lives in `.claude-flow/sessions/pair/current.json`. `ruflo pair end` archives it to `history.jsonl` next to it.
32
+
22
33
  ## Prerequisites
23
34
 
24
35
  **Required:**
25
- - Claude Flow CLI installed (`npm install -g claude-flow@alpha`)
36
+ - Ruflo CLI installed (`npm install -g ruflo`), which provides the `ruflo pair` command
26
37
  - Git repository (optional but recommended)
27
38
 
28
39
  **Recommended:**
@@ -35,13 +46,13 @@ This skill provides professional pair programming capabilities with AI assistanc
35
46
  ### Basic Session
36
47
  ```bash
37
48
  # Start simple pair programming
38
- claude-flow pair --start
49
+ ruflo pair start
39
50
  ```
40
51
 
41
52
  ### TDD Session
42
53
  ```bash
43
54
  # Test-driven development
44
- claude-flow pair --start \
55
+ ruflo pair start \
45
56
  --mode tdd \
46
57
  --test-first \
47
58
  --coverage 90
@@ -56,23 +67,23 @@ claude-flow pair --start \
56
67
  #### Starting Sessions
57
68
  ```bash
58
69
  # Basic start
59
- claude-flow pair --start
70
+ ruflo pair start
60
71
 
61
72
  # Expert refactoring session
62
- claude-flow pair --start \
73
+ ruflo pair start \
63
74
  --agent senior-dev \
64
75
  --focus refactor \
65
76
  --verify \
66
77
  --threshold 0.98
67
78
 
68
79
  # Debugging session
69
- claude-flow pair --start \
80
+ ruflo pair start \
70
81
  --agent debugger-expert \
71
82
  --focus debug \
72
83
  --review
73
84
 
74
85
  # Learning session
75
- claude-flow pair --start \
86
+ ruflo pair start \
76
87
  --mode mentor \
77
88
  --pace slow \
78
89
  --examples
@@ -81,10 +92,10 @@ claude-flow pair --start \
81
92
  #### Session Management
82
93
  ```bash
83
94
  # Check status
84
- claude-flow pair --status
95
+ ruflo pair status
85
96
 
86
97
  # View history
87
- claude-flow pair --history
98
+ ruflo pair history
88
99
 
89
100
  # Pause session
90
101
  /pause [--reason <reason>]
@@ -93,7 +104,7 @@ claude-flow pair --history
93
104
  /resume
94
105
 
95
106
  # End session
96
- claude-flow pair --end [--save] [--report]
107
+ ruflo pair end [--save] [--report]
97
108
  ```
98
109
 
99
110
  ### Available Modes
@@ -102,7 +113,7 @@ claude-flow pair --end [--save] [--report]
102
113
  You write code while AI provides guidance.
103
114
 
104
115
  ```bash
105
- claude-flow pair --start --mode driver
116
+ ruflo pair start --mode driver
106
117
  ```
107
118
 
108
119
  **Your Responsibilities:**
@@ -137,7 +148,7 @@ claude-flow pair --start --mode driver
137
148
  AI writes code while you provide direction.
138
149
 
139
150
  ```bash
140
- claude-flow pair --start --mode navigator
151
+ ruflo pair start --mode navigator
141
152
  ```
142
153
 
143
154
  **Your Responsibilities:**
@@ -173,13 +184,13 @@ Automatically alternates roles at intervals.
173
184
 
174
185
  ```bash
175
186
  # Default 10-minute intervals
176
- claude-flow pair --start --mode switch
187
+ ruflo pair start --mode switch
177
188
 
178
189
  # 5-minute intervals (rapid)
179
- claude-flow pair --start --mode switch --interval 5m
190
+ ruflo pair start --mode switch --interval 5m
180
191
 
181
192
  # 15-minute intervals (deep focus)
182
- claude-flow pair --start --mode switch --interval 15m
193
+ ruflo pair start --mode switch --interval 15m
183
194
  ```
184
195
 
185
196
  **Handoff Process:**
@@ -199,7 +210,7 @@ claude-flow pair --start --mode switch --interval 15m
199
210
 
200
211
  **TDD Mode** - Test-Driven Development:
201
212
  ```bash
202
- claude-flow pair --start \
213
+ ruflo pair start \
203
214
  --mode tdd \
204
215
  --test-first \
205
216
  --coverage 100
@@ -208,7 +219,7 @@ Workflow: Write failing test → Implement → Refactor → Repeat
208
219
 
209
220
  **Review Mode** - Continuous code review:
210
221
  ```bash
211
- claude-flow pair --start \
222
+ ruflo pair start \
212
223
  --mode review \
213
224
  --strict \
214
225
  --security
@@ -217,7 +228,7 @@ Features: Real-time feedback, security scanning, performance analysis
217
228
 
218
229
  **Mentor Mode** - Learning-focused:
219
230
  ```bash
220
- claude-flow pair --start \
231
+ ruflo pair start \
221
232
  --mode mentor \
222
233
  --explain-all \
223
234
  --pace slow
@@ -226,7 +237,7 @@ Features: Detailed explanations, step-by-step guidance, pattern teaching
226
237
 
227
238
  **Debug Mode** - Problem-solving:
228
239
  ```bash
229
- claude-flow pair --start \
240
+ ruflo pair start \
230
241
  --mode debug \
231
242
  --verbose \
232
243
  --trace
@@ -559,19 +570,19 @@ Create `.claude-flow/pair-config.json`:
559
570
  #### CLI Configuration
560
571
  ```bash
561
572
  # Set configuration
562
- claude-flow pair config set defaultMode switch
563
- claude-flow pair config set verification.threshold 0.98
573
+ ruflo pair config set defaultMode switch
574
+ ruflo pair config set verification.threshold 0.98
564
575
 
565
576
  # Get configuration
566
- claude-flow pair config get
567
- claude-flow pair config get defaultMode
577
+ ruflo pair config get
578
+ ruflo pair config get defaultMode
568
579
 
569
580
  # Export/Import
570
- claude-flow pair config export > config.json
571
- claude-flow pair config import config.json
581
+ ruflo pair config export > config.json
582
+ ruflo pair config import config.json
572
583
 
573
584
  # Reset
574
- claude-flow pair config reset
585
+ ruflo pair config reset
575
586
  ```
576
587
 
577
588
  #### Profile Management
@@ -580,17 +591,17 @@ Create reusable profiles:
580
591
 
581
592
  ```bash
582
593
  # Create profile
583
- claude-flow pair profile create refactoring \
594
+ ruflo pair profile create refactoring \
584
595
  --mode driver \
585
596
  --verify true \
586
597
  --threshold 0.98 \
587
598
  --focus refactor
588
599
 
589
600
  # Use profile
590
- claude-flow pair --start --profile refactoring
601
+ ruflo pair start --profile refactoring
591
602
 
592
603
  # List profiles
593
- claude-flow pair profile list
604
+ ruflo pair profile list
594
605
  ```
595
606
 
596
607
  Profile configuration:
@@ -629,7 +640,7 @@ Implementing user authentication with JWT tokens:
629
640
 
630
641
  ```bash
631
642
  # Session setup
632
- claude-flow pair --start \
643
+ ruflo pair start \
633
644
  --mode switch \
634
645
  --agent senior-dev \
635
646
  --focus implement \
@@ -676,7 +687,7 @@ Debugging a memory leak in Node.js:
676
687
 
677
688
  ```bash
678
689
  # Session setup
679
- claude-flow pair --start \
690
+ ruflo pair start \
680
691
  --mode navigator \
681
692
  --agent debugger-expert \
682
693
  --focus debug \
@@ -717,7 +728,7 @@ Building shopping cart with test-driven development:
717
728
 
718
729
  ```bash
719
730
  # Session setup
720
- claude-flow pair --start \
731
+ ruflo pair start \
721
732
  --mode tdd \
722
733
  --agent tdd-specialist \
723
734
  --test-first
@@ -759,7 +770,7 @@ Modernizing legacy code:
759
770
 
760
771
  ```bash
761
772
  # Session setup
762
- claude-flow pair --start \
773
+ ruflo pair start \
763
774
  --mode driver \
764
775
  --focus refactor \
765
776
  --verify \
@@ -807,7 +818,7 @@ Optimizing slow React application:
807
818
 
808
819
  ```bash
809
820
  # Session setup
810
- claude-flow pair --start \
821
+ ruflo pair start \
811
822
  --mode switch \
812
823
  --agent performance-expert \
813
824
  --focus optimize \
@@ -852,7 +863,7 @@ Building RESTful API with Express:
852
863
 
853
864
  ```bash
854
865
  # Session setup
855
- claude-flow pair --start \
866
+ ruflo pair start \
856
867
  --mode navigator \
857
868
  --agent backend-expert \
858
869
  --focus implement \
@@ -897,28 +908,28 @@ claude-flow pair --start \
897
908
 
898
909
  ```bash
899
910
  # Refactoring template
900
- claude-flow pair --template refactor
911
+ ruflo pair --template refactor
901
912
  # Focus: Code improvement
902
913
  # Verification: High (0.98)
903
914
  # Testing: After each change
904
915
  # Review: Continuous
905
916
 
906
917
  # Feature template
907
- claude-flow pair --template feature
918
+ ruflo pair --template feature
908
919
  # Focus: Implementation
909
920
  # Verification: Standard (0.95)
910
921
  # Testing: On completion
911
922
  # Review: Pre-commit
912
923
 
913
924
  # Debug template
914
- claude-flow pair --template debug
925
+ ruflo pair --template debug
915
926
  # Focus: Problem solving
916
927
  # Verification: Moderate (0.90)
917
928
  # Testing: Regression tests
918
929
  # Review: Root cause
919
930
 
920
931
  # Learning template
921
- claude-flow pair --template learn
932
+ ruflo pair --template learn
922
933
  # Mode: Mentor
923
934
  # Pace: Slow
924
935
  # Explanations: Detailed
@@ -930,7 +941,7 @@ claude-flow pair --template learn
930
941
  #### Session Status
931
942
 
932
943
  ```bash
933
- claude-flow pair --status
944
+ ruflo pair status
934
945
  ```
935
946
 
936
947
  **Output:**
@@ -962,7 +973,7 @@ Next Switch: in 3 minutes
962
973
  #### Session History
963
974
 
964
975
  ```bash
965
- claude-flow pair --history
976
+ ruflo pair history
966
977
  ```
967
978
 
968
979
  **Output:**
@@ -993,32 +1004,32 @@ claude-flow pair --history
993
1004
 
994
1005
  ```bash
995
1006
  # Save session
996
- claude-flow pair --save [--name <name>]
1007
+ ruflo pair --save [--name <name>]
997
1008
 
998
1009
  # Load session
999
- claude-flow pair --load <session-id>
1010
+ ruflo pair --load <session-id>
1000
1011
 
1001
1012
  # Export session
1002
- claude-flow pair --export <session-id> [--format json|md]
1013
+ ruflo pair --export <session-id> [--format json|md]
1003
1014
 
1004
1015
  # Generate report
1005
- claude-flow pair --report <session-id>
1016
+ ruflo pair --report <session-id>
1006
1017
  ```
1007
1018
 
1008
1019
  #### Background Sessions
1009
1020
 
1010
1021
  ```bash
1011
1022
  # Start in background
1012
- claude-flow pair --start --background
1023
+ ruflo pair start --background
1013
1024
 
1014
1025
  # Monitor background session
1015
- claude-flow pair --monitor
1026
+ ruflo pair --monitor
1016
1027
 
1017
1028
  # Attach to background session
1018
- claude-flow pair --attach <session-id>
1029
+ ruflo pair --attach <session-id>
1019
1030
 
1020
1031
  # End background session
1021
- claude-flow pair --end <session-id>
1032
+ ruflo pair end <session-id>
1022
1033
  ```
1023
1034
 
1024
1035
  ### Advanced Features
@@ -1054,30 +1065,30 @@ Use custom commands:
1054
1065
 
1055
1066
  ```bash
1056
1067
  # Start with recording
1057
- claude-flow pair --start --record
1068
+ ruflo pair start --record
1058
1069
 
1059
1070
  # Replay session
1060
- claude-flow pair --replay <session-id>
1071
+ ruflo pair --replay <session-id>
1061
1072
 
1062
1073
  # Session analytics
1063
- claude-flow pair --analytics <session-id>
1074
+ ruflo pair --analytics <session-id>
1064
1075
  ```
1065
1076
 
1066
1077
  #### Integration Options
1067
1078
 
1068
1079
  **With Git:**
1069
1080
  ```bash
1070
- claude-flow pair --start --git --auto-commit
1081
+ ruflo pair start --git --auto-commit
1071
1082
  ```
1072
1083
 
1073
1084
  **With CI/CD:**
1074
1085
  ```bash
1075
- claude-flow pair --start --ci --non-interactive
1086
+ ruflo pair start --ci --non-interactive
1076
1087
  ```
1077
1088
 
1078
1089
  **With IDE:**
1079
1090
  ```bash
1080
- claude-flow pair --start --ide vscode
1091
+ ruflo pair start --ide vscode
1081
1092
  ```
1082
1093
 
1083
1094
  ### Best Practices
@@ -1131,7 +1142,7 @@ claude-flow pair --start --ide vscode
1131
1142
  - Validate JSON syntax
1132
1143
  - Check file permissions
1133
1144
  - Review priority order (CLI > env > project > user > global)
1134
- - Run `claude-flow pair config validate`
1145
+ - Run `ruflo pair config validate`
1135
1146
 
1136
1147
  ### Quality Metrics
1137
1148
 
@@ -1195,8 +1206,8 @@ Default shortcuts:
1195
1206
 
1196
1207
  ### Related Commands
1197
1208
 
1198
- - `claude-flow pair --help` - Show help
1199
- - `claude-flow pair config` - Manage configuration
1200
- - `claude-flow pair profile` - Manage profiles
1201
- - `claude-flow pair templates` - List templates
1202
- - `claude-flow pair agents` - List available agents
1209
+ - `ruflo pair --help` - Show help
1210
+ - `ruflo pair config` - Manage configuration
1211
+ - `ruflo pair profile` - Manage profiles
1212
+ - `ruflo pair templates` - List templates
1213
+ - `ruflo pair agents` - List available agents
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-flow",
3
- "version": "3.59.10",
3
+ "version": "3.59.12",
4
4
  "workspaces": [
5
5
  "v3/@claude-flow/codex",
6
6
  "v3/@claude-flow/mcp",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "generation": 7,
4
- "generatedAt": "2026-10-21T18:10:57.425Z",
5
- "gitSha": "2e0036af",
4
+ "generatedAt": "2026-10-21T20:45:54.432Z",
5
+ "gitSha": "c7646541",
6
6
  "catalog": {
7
7
  "agents": 176,
8
8
  "tools": 432,
@@ -47,8 +47,8 @@ export const signCommand = {
47
47
  action: async (ctx) => {
48
48
  const file = ctx.flags.file;
49
49
  const keyPath = ctx.flags.key;
50
- const genKeys = ctx.flags['generate-keys'];
51
- const keyDir = ctx.flags['key-dir'] || '.rvfa-keys';
50
+ const genKeys = ctx.flags.generateKeys;
51
+ const keyDir = ctx.flags.keyDir || '.rvfa-keys';
52
52
  const signer = ctx.flags.signer;
53
53
  if (!file)
54
54
  return fail('--file is required');
@@ -184,14 +184,14 @@ export const updateAppCommand = {
184
184
  });
185
185
  }
186
186
  let pubKey;
187
- if (ctx.flags['public-key']) {
188
- const pkPath = ctx.flags['public-key'];
187
+ if (ctx.flags.publicKey) {
188
+ const pkPath = ctx.flags.publicKey;
189
189
  if (!(await requireFile(pkPath)))
190
190
  return { success: false, exitCode: 1 };
191
191
  pubKey = fs.readFileSync(pkPath);
192
192
  }
193
193
  const result = await dist.RvfaPatcher.applyPatch(file, patchBuf, {
194
- backup: !ctx.flags['no-backup'],
194
+ backup: ctx.flags.backup !== false,
195
195
  verify: true,
196
196
  publicKey: pubKey,
197
197
  });
@@ -70,7 +70,7 @@ const buildCommand = {
70
70
  const outputPath = ctx.flags.output || 'ruflo.rvf';
71
71
  const arch = ctx.flags.arch || 'x86_64';
72
72
  const models = ctx.flags.models || [];
73
- const apiKeysPath = ctx.flags['api-keys'];
73
+ const apiKeysPath = ctx.flags.apiKeys;
74
74
  header('RVFA Appliance Builder');
75
75
  output.printInfo(`Profile: ${output.highlight(profile)}`);
76
76
  output.printInfo(`Arch: ${arch}`);
@@ -92,7 +92,10 @@ const buildCommand = {
92
92
  if (apiKeysPath)
93
93
  steps.splice(steps.length - 1, 0, 'Sealing API key vault');
94
94
  try {
95
- const builder = new RvfaBuilder({ profile, outputPath, arch, models, apiKeysPath });
95
+ const builder = new RvfaBuilder({
96
+ profile, output: outputPath, arch, apiKeys: apiKeysPath,
97
+ models: models.length > 0 ? models : undefined,
98
+ });
96
99
  await runSteps(steps);
97
100
  const result = await builder.build();
98
101
  const duration = ((Date.now() - startTime) / 1000).toFixed(1);
@@ -108,7 +111,7 @@ const buildCommand = {
108
111
  }
109
112
  output.writeln();
110
113
  output.printSuccess(`Appliance written to ${output.bold(outputPath)}`);
111
- output.printInfo(`Total size: ${output.bold(fmtSize(result.totalSize))} Duration: ${duration}s`);
114
+ output.printInfo(`Total size: ${output.bold(fmtSize(result.size))} Duration: ${duration}s`);
112
115
  return { success: true, data: result };
113
116
  }
114
117
  catch (err) {
@@ -46,6 +46,7 @@ export declare function getGuidanceCommand(): Promise<Command | undefined>;
46
46
  export declare function getApplianceCommand(): Promise<Command | undefined>;
47
47
  export declare function getCleanupCommand(): Promise<Command | undefined>;
48
48
  export declare function getAutopilotCommand(): Promise<Command | undefined>;
49
+ export declare function getPairCommand(): Promise<Command | undefined>;
49
50
  export declare function getTransportCommand(): Promise<Command | undefined>;
50
51
  /**
51
52
  * Core commands loaded synchronously (available immediately)
@@ -70,6 +70,9 @@ const commandLoaders = {
70
70
  'transfer-store': () => import('./transfer-store.js'),
71
71
  cleanup: () => import('./cleanup.js'),
72
72
  autopilot: () => import('./autopilot.js'),
73
+ // Pair programming session state (restores the v2 `pair` command the
74
+ // bundled pair-programming skill depends on)
75
+ pair: () => import('./pair.js'),
73
76
  // GAIA Benchmark Harness (ADR-133)
74
77
  'gaia-bench': () => import('./gaia-bench.js'),
75
78
  // MetaHarness integration (ADR-150) — dispatcher over plugins/ruflo-metaharness/
@@ -203,6 +206,7 @@ export async function getGuidanceCommand() { return loadCommand('guidance'); }
203
206
  export async function getApplianceCommand() { return loadCommand('appliance'); }
204
207
  export async function getCleanupCommand() { return loadCommand('cleanup'); }
205
208
  export async function getAutopilotCommand() { return loadCommand('autopilot'); }
209
+ export async function getPairCommand() { return loadCommand('pair'); }
206
210
  export async function getTransportCommand() { return loadCommand('transport'); }
207
211
  /**
208
212
  * Core commands loaded synchronously (available immediately)
@@ -249,14 +253,14 @@ export const commandsByCategory = {
249
253
  * Use this for help display and full command listings.
250
254
  */
251
255
  export async function getCommandsByCategory() {
252
- const [daemonCmd, doctorCmd, embeddingsCmd, neuralCmd, performanceCmd, securityCmd, ruvectorCmd, hiveMindCmd, configCmd, completionsCmd, migrateCmd, workflowCmd, analyzeCmd, routeCmd, progressCmd, providersCmd, pluginsCmd, deploymentCmd, claimsCmd, issuesCmd, updateCmd, processCmd, guidanceCmd, applianceCmd, cleanupCmd, autopilotCmd, policyCmd,] = await Promise.all([
256
+ const [daemonCmd, doctorCmd, embeddingsCmd, neuralCmd, performanceCmd, securityCmd, ruvectorCmd, hiveMindCmd, configCmd, completionsCmd, migrateCmd, workflowCmd, analyzeCmd, routeCmd, progressCmd, providersCmd, pluginsCmd, deploymentCmd, claimsCmd, issuesCmd, updateCmd, processCmd, guidanceCmd, applianceCmd, cleanupCmd, autopilotCmd, policyCmd, pairCmd,] = await Promise.all([
253
257
  loadCommand('daemon'), loadCommand('doctor'), loadCommand('embeddings'), loadCommand('neural'),
254
258
  loadCommand('performance'), loadCommand('security'), loadCommand('ruvector'), loadCommand('hive-mind'),
255
259
  loadCommand('config'), loadCommand('completions'), loadCommand('migrate'), loadCommand('workflow'),
256
260
  loadCommand('analyze'), loadCommand('route'), loadCommand('progress'), loadCommand('providers'),
257
261
  loadCommand('plugins'), loadCommand('deployment'), loadCommand('claims'), loadCommand('issues'),
258
262
  loadCommand('update'), loadCommand('process'), loadCommand('guidance'), loadCommand('appliance'),
259
- loadCommand('cleanup'), loadCommand('autopilot'), loadCommand('policy'),
263
+ loadCommand('cleanup'), loadCommand('autopilot'), loadCommand('policy'), loadCommand('pair'),
260
264
  ]);
261
265
  return {
262
266
  primary: [
@@ -270,7 +274,7 @@ export async function getCommandsByCategory() {
270
274
  ].filter(Boolean),
271
275
  utility: [
272
276
  configCmd, doctorCmd, daemonCmd, completionsCmd,
273
- migrateCmd, workflowCmd,
277
+ migrateCmd, workflowCmd, pairCmd,
274
278
  ].filter(Boolean),
275
279
  analysis: [
276
280
  analyzeCmd, routeCmd, progressCmd,
@@ -0,0 +1,46 @@
1
+ /**
2
+ * `ruflo pair` — pair programming session state.
3
+ *
4
+ * The bundled `pair-programming` skill has told Claude Code to run
5
+ * `claude-flow pair --start --mode tdd` since v2, but the v3 CLI never
6
+ * shipped the command, so the skill's modes could not be activated or
7
+ * switched. This restores a minimal, non-interactive version: the session
8
+ * (mode, who currently drives, when roles last swapped) lives in
9
+ * `.claude-flow/sessions/pair/current.json` in the project so both the human
10
+ * and the agent can read it between turns. There is no REPL — Claude Code
11
+ * cannot type into one — the agent reads `pair status --json` and behaves
12
+ * according to the recorded mode and role.
13
+ *
14
+ * Legacy v2 spellings (`pair --start`, `--status`, `--end`, `--history`)
15
+ * still work so existing skill docs and muscle memory keep functioning.
16
+ */
17
+ import type { Command } from '../types.js';
18
+ export declare const PAIR_MODES: {
19
+ readonly driver: "AI writes the code, human reviews and steers";
20
+ readonly navigator: "Human writes the code, AI reviews and suggests";
21
+ readonly switch: "Roles swap every --interval (default 10m)";
22
+ readonly tdd: "Red-green-refactor; AI writes failing tests first";
23
+ readonly review: "Read-only review of existing code, no edits without approval";
24
+ readonly mentor: "AI explains every step and asks before acting";
25
+ readonly debug: "Hypothesis-driven debugging; AI reproduces before fixing";
26
+ };
27
+ export type PairMode = keyof typeof PAIR_MODES;
28
+ export type PairRole = 'driver' | 'navigator';
29
+ export interface PairSession {
30
+ id: string;
31
+ mode: PairMode;
32
+ /** Who currently types. Always refers to the AI's role. */
33
+ aiRole: PairRole;
34
+ switchIntervalMinutes: number | null;
35
+ startedAt: string;
36
+ lastSwitchAt: string;
37
+ switches: number;
38
+ endedAt?: string;
39
+ }
40
+ export declare function readSession(cwd: string): PairSession | null;
41
+ export declare function readHistory(cwd: string): PairSession[];
42
+ /** Accepts `10`, `10m`, `1h`, `90s`; returns minutes or null when unparseable. */
43
+ export declare function parseIntervalMinutes(raw: unknown): number | null;
44
+ export declare const pairCommand: Command;
45
+ export default pairCommand;
46
+ //# sourceMappingURL=pair.d.ts.map
@@ -0,0 +1,303 @@
1
+ /**
2
+ * `ruflo pair` — pair programming session state.
3
+ *
4
+ * The bundled `pair-programming` skill has told Claude Code to run
5
+ * `claude-flow pair --start --mode tdd` since v2, but the v3 CLI never
6
+ * shipped the command, so the skill's modes could not be activated or
7
+ * switched. This restores a minimal, non-interactive version: the session
8
+ * (mode, who currently drives, when roles last swapped) lives in
9
+ * `.claude-flow/sessions/pair/current.json` in the project so both the human
10
+ * and the agent can read it between turns. There is no REPL — Claude Code
11
+ * cannot type into one — the agent reads `pair status --json` and behaves
12
+ * according to the recorded mode and role.
13
+ *
14
+ * Legacy v2 spellings (`pair --start`, `--status`, `--end`, `--history`)
15
+ * still work so existing skill docs and muscle memory keep functioning.
16
+ */
17
+ import * as fs from 'node:fs';
18
+ import * as path from 'node:path';
19
+ import { output } from '../output.js';
20
+ export const PAIR_MODES = {
21
+ driver: 'AI writes the code, human reviews and steers',
22
+ navigator: 'Human writes the code, AI reviews and suggests',
23
+ switch: 'Roles swap every --interval (default 10m)',
24
+ tdd: 'Red-green-refactor; AI writes failing tests first',
25
+ review: 'Read-only review of existing code, no edits without approval',
26
+ mentor: 'AI explains every step and asks before acting',
27
+ debug: 'Hypothesis-driven debugging; AI reproduces before fixing',
28
+ };
29
+ const SESSION_DIR = ['.claude-flow', 'sessions', 'pair'];
30
+ const DEFAULT_SWITCH_INTERVAL_MINUTES = 10;
31
+ function sessionDir(cwd) {
32
+ return path.join(cwd, ...SESSION_DIR);
33
+ }
34
+ function currentPath(cwd) {
35
+ return path.join(sessionDir(cwd), 'current.json');
36
+ }
37
+ function historyPath(cwd) {
38
+ return path.join(sessionDir(cwd), 'history.jsonl');
39
+ }
40
+ export function readSession(cwd) {
41
+ try {
42
+ return JSON.parse(fs.readFileSync(currentPath(cwd), 'utf-8'));
43
+ }
44
+ catch {
45
+ return null;
46
+ }
47
+ }
48
+ function writeSession(cwd, session) {
49
+ fs.mkdirSync(sessionDir(cwd), { recursive: true });
50
+ const tmp = currentPath(cwd) + '.tmp-' + process.pid;
51
+ fs.writeFileSync(tmp, JSON.stringify(session, null, 2) + '\n', 'utf-8');
52
+ fs.renameSync(tmp, currentPath(cwd));
53
+ }
54
+ export function readHistory(cwd) {
55
+ try {
56
+ return fs.readFileSync(historyPath(cwd), 'utf-8')
57
+ .split('\n')
58
+ .filter(Boolean)
59
+ .map(line => JSON.parse(line));
60
+ }
61
+ catch {
62
+ return [];
63
+ }
64
+ }
65
+ /** Accepts `10`, `10m`, `1h`, `90s`; returns minutes or null when unparseable. */
66
+ export function parseIntervalMinutes(raw) {
67
+ if (raw === undefined || raw === null || raw === '')
68
+ return null;
69
+ if (typeof raw === 'number')
70
+ return raw > 0 ? raw : null;
71
+ const match = /^(\d+(?:\.\d+)?)\s*(s|m|h)?$/i.exec(String(raw).trim());
72
+ if (!match)
73
+ return null;
74
+ const value = parseFloat(match[1]);
75
+ const unit = (match[2] ?? 'm').toLowerCase();
76
+ const minutes = unit === 'h' ? value * 60 : unit === 's' ? value / 60 : value;
77
+ return minutes > 0 ? minutes : null;
78
+ }
79
+ function isMode(value) {
80
+ return typeof value === 'string' && value in PAIR_MODES;
81
+ }
82
+ function otherRole(role) {
83
+ return role === 'driver' ? 'navigator' : 'driver';
84
+ }
85
+ /** Default AI role implied by a mode, used when --role is not given. */
86
+ function defaultRoleFor(mode) {
87
+ return mode === 'navigator' || mode === 'review' ? 'navigator' : 'driver';
88
+ }
89
+ function switchDue(session, now) {
90
+ if (session.mode !== 'switch' || !session.switchIntervalMinutes)
91
+ return false;
92
+ const elapsedMinutes = (now.getTime() - new Date(session.lastSwitchAt).getTime()) / 60_000;
93
+ return elapsedMinutes >= session.switchIntervalMinutes;
94
+ }
95
+ function describe(session, now) {
96
+ return {
97
+ ...session,
98
+ modeDescription: PAIR_MODES[session.mode],
99
+ humanRole: otherRole(session.aiRole),
100
+ switchDue: switchDue(session, now),
101
+ };
102
+ }
103
+ function printSession(session, now) {
104
+ output.writeln(`Session: ${session.id}`);
105
+ output.writeln(`Mode: ${session.mode} — ${PAIR_MODES[session.mode]}`);
106
+ output.writeln(`AI role: ${session.aiRole} (human: ${otherRole(session.aiRole)})`);
107
+ if (session.switchIntervalMinutes) {
108
+ output.writeln(`Interval: every ${session.switchIntervalMinutes}m, ${session.switches} switch(es) so far`);
109
+ if (switchDue(session, now))
110
+ output.printWarning('Role switch is due — run `ruflo pair switch`.');
111
+ }
112
+ output.writeln(`Started: ${session.startedAt}`);
113
+ }
114
+ function noSession(ctx) {
115
+ if (ctx.flags.json)
116
+ output.printJson({ active: false });
117
+ else
118
+ output.writeln('No active pair session. Start one with `ruflo pair start --mode <mode>`.');
119
+ return { success: true, data: { active: false } };
120
+ }
121
+ async function startAction(ctx) {
122
+ // `pair start tdd` and `pair start --mode tdd` both work; a bare word wins
123
+ // over the option default so it is never silently ignored.
124
+ const mode = ctx.args[0] ?? ctx.flags.mode ?? 'driver';
125
+ if (!isMode(mode)) {
126
+ output.printError(`Unknown mode "${String(mode)}". Choose one of: ${Object.keys(PAIR_MODES).join(', ')}`);
127
+ return { success: false, exitCode: 1 };
128
+ }
129
+ const existing = readSession(ctx.cwd);
130
+ if (existing) {
131
+ output.printError(`A pair session is already active (${existing.id}). End it first with \`ruflo pair end\`.`);
132
+ return { success: false, exitCode: 1, data: describe(existing, new Date()) };
133
+ }
134
+ const interval = ctx.flags.interval !== undefined ? parseIntervalMinutes(ctx.flags.interval) : null;
135
+ if (ctx.flags.interval !== undefined && interval === null) {
136
+ output.printError(`Invalid --interval "${String(ctx.flags.interval)}". Use e.g. 10m, 90s or 1h.`);
137
+ return { success: false, exitCode: 1 };
138
+ }
139
+ const role = ctx.flags.role;
140
+ const now = new Date();
141
+ const session = {
142
+ id: `pair_${now.getTime()}`,
143
+ mode,
144
+ aiRole: role === 'driver' || role === 'navigator' ? role : defaultRoleFor(mode),
145
+ switchIntervalMinutes: mode === 'switch' ? (interval ?? DEFAULT_SWITCH_INTERVAL_MINUTES) : interval,
146
+ startedAt: now.toISOString(),
147
+ lastSwitchAt: now.toISOString(),
148
+ switches: 0,
149
+ };
150
+ writeSession(ctx.cwd, session);
151
+ if (ctx.flags.json)
152
+ output.printJson(describe(session, now));
153
+ else {
154
+ output.printSuccess('Pair session started.');
155
+ printSession(session, now);
156
+ }
157
+ return { success: true, data: describe(session, now) };
158
+ }
159
+ const startSub = {
160
+ name: 'start',
161
+ description: 'Start a pair programming session',
162
+ options: [
163
+ { name: 'mode', short: 'm', description: 'Collaboration mode', type: 'string', default: 'driver', choices: Object.keys(PAIR_MODES) },
164
+ { name: 'role', description: "AI's starting role (defaults from mode)", type: 'string', choices: ['driver', 'navigator'] },
165
+ { name: 'interval', short: 'i', description: 'Role switch interval for switch mode (e.g. 10m, 1h)', type: 'string' },
166
+ { name: 'json', description: 'Output as JSON', type: 'boolean', default: false },
167
+ ],
168
+ action: startAction,
169
+ };
170
+ async function statusAction(ctx) {
171
+ const session = readSession(ctx.cwd);
172
+ if (!session)
173
+ return noSession(ctx);
174
+ const now = new Date();
175
+ if (ctx.flags.json)
176
+ output.printJson({ active: true, ...describe(session, now) });
177
+ else
178
+ printSession(session, now);
179
+ return { success: true, data: { active: true, ...describe(session, now) } };
180
+ }
181
+ const statusSub = {
182
+ name: 'status',
183
+ description: 'Show the active pair session',
184
+ options: [{ name: 'json', description: 'Output as JSON', type: 'boolean', default: false }],
185
+ action: statusAction,
186
+ };
187
+ async function switchAction(ctx) {
188
+ const session = readSession(ctx.cwd);
189
+ if (!session)
190
+ return noSession(ctx);
191
+ const now = new Date();
192
+ session.aiRole = otherRole(session.aiRole);
193
+ session.lastSwitchAt = now.toISOString();
194
+ session.switches += 1;
195
+ writeSession(ctx.cwd, session);
196
+ if (ctx.flags.json)
197
+ output.printJson(describe(session, now));
198
+ else
199
+ output.printSuccess(`Switched — AI is now ${session.aiRole}, human is ${otherRole(session.aiRole)}.`);
200
+ return { success: true, data: describe(session, now) };
201
+ }
202
+ const switchSub = {
203
+ name: 'switch',
204
+ description: 'Swap driver and navigator roles',
205
+ options: [{ name: 'json', description: 'Output as JSON', type: 'boolean', default: false }],
206
+ action: switchAction,
207
+ };
208
+ async function modeAction(ctx) {
209
+ const session = readSession(ctx.cwd);
210
+ if (!session)
211
+ return noSession(ctx);
212
+ const mode = ctx.args[0];
213
+ if (!isMode(mode)) {
214
+ output.printError(`Usage: ruflo pair mode <${Object.keys(PAIR_MODES).join('|')}>`);
215
+ return { success: false, exitCode: 1 };
216
+ }
217
+ const now = new Date();
218
+ session.mode = mode;
219
+ if (mode === 'switch' && !session.switchIntervalMinutes) {
220
+ session.switchIntervalMinutes = DEFAULT_SWITCH_INTERVAL_MINUTES;
221
+ session.lastSwitchAt = now.toISOString();
222
+ }
223
+ writeSession(ctx.cwd, session);
224
+ if (ctx.flags.json)
225
+ output.printJson(describe(session, now));
226
+ else
227
+ output.printSuccess(`Mode changed to ${mode} — ${PAIR_MODES[mode]}.`);
228
+ return { success: true, data: describe(session, now) };
229
+ }
230
+ const modeSub = {
231
+ name: 'mode',
232
+ description: 'Change the mode of the active session: ruflo pair mode <mode>',
233
+ options: [{ name: 'json', description: 'Output as JSON', type: 'boolean', default: false }],
234
+ action: modeAction,
235
+ };
236
+ async function endAction(ctx) {
237
+ const session = readSession(ctx.cwd);
238
+ if (!session)
239
+ return noSession(ctx);
240
+ session.endedAt = new Date().toISOString();
241
+ fs.appendFileSync(historyPath(ctx.cwd), JSON.stringify(session) + '\n', 'utf-8');
242
+ fs.rmSync(currentPath(ctx.cwd), { force: true });
243
+ if (ctx.flags.json)
244
+ output.printJson(session);
245
+ else
246
+ output.printSuccess(`Pair session ${session.id} ended after ${session.switches} role switch(es).`);
247
+ return { success: true, data: session };
248
+ }
249
+ const endSub = {
250
+ name: 'end',
251
+ description: 'End the active session and append it to the history',
252
+ options: [{ name: 'json', description: 'Output as JSON', type: 'boolean', default: false }],
253
+ action: endAction,
254
+ };
255
+ async function historyAction(ctx) {
256
+ const history = readHistory(ctx.cwd);
257
+ if (ctx.flags.json)
258
+ output.printJson(history);
259
+ else if (history.length === 0)
260
+ output.writeln('No past pair sessions.');
261
+ else
262
+ for (const s of history)
263
+ output.writeln(`${s.id} ${s.mode.padEnd(9)} ${s.startedAt} → ${s.endedAt ?? '?'} (${s.switches} switches)`);
264
+ return { success: true, data: history };
265
+ }
266
+ const historySub = {
267
+ name: 'history',
268
+ description: 'List past pair sessions',
269
+ options: [{ name: 'json', description: 'Output as JSON', type: 'boolean', default: false }],
270
+ action: historyAction,
271
+ };
272
+ export const pairCommand = {
273
+ name: 'pair',
274
+ description: 'Pair programming session: modes, driver/navigator roles, switching',
275
+ subcommands: [startSub, statusSub, switchSub, modeSub, endSub, historySub],
276
+ // Top-level flags kept for the v2 spelling used throughout the skill docs.
277
+ options: [
278
+ { name: 'start', description: 'Alias for `pair start`', type: 'boolean', default: false },
279
+ { name: 'status', description: 'Alias for `pair status`', type: 'boolean', default: false },
280
+ { name: 'end', description: 'Alias for `pair end`', type: 'boolean', default: false },
281
+ { name: 'history', description: 'Alias for `pair history`', type: 'boolean', default: false },
282
+ ...(startSub.options ?? []),
283
+ ],
284
+ examples: [
285
+ { command: 'ruflo pair start --mode tdd', description: 'Start a test-first session with the AI driving' },
286
+ { command: 'ruflo pair start --mode switch --interval 15m', description: 'Swap roles every 15 minutes' },
287
+ { command: 'ruflo pair status --json', description: 'Machine-readable state for the agent to read each turn' },
288
+ { command: 'ruflo pair switch', description: 'Swap driver and navigator now' },
289
+ { command: 'ruflo pair mode review', description: 'Change mode mid-session' },
290
+ { command: 'ruflo pair end', description: 'End the session and record it in the history' },
291
+ ],
292
+ action: async (ctx) => {
293
+ if (ctx.flags.start)
294
+ return startAction(ctx);
295
+ if (ctx.flags.end)
296
+ return endAction(ctx);
297
+ if (ctx.flags.history)
298
+ return historyAction(ctx);
299
+ return statusAction(ctx);
300
+ },
301
+ };
302
+ export default pairCommand;
303
+ //# sourceMappingURL=pair.js.map
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claude-flow/cli",
3
- "version": "3.59.10",
3
+ "version": "3.59.12",
4
4
  "type": "module",
5
5
  "description": "Ruflo CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
6
6
  "main": "dist/src/index.js",