rafcode 2.5.0-0 → 2.5.1-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.
Files changed (60) hide show
  1. package/CLAUDE.md +1 -1
  2. package/RAF/ahwvrz-legacy-sunset/decisions.md +10 -0
  3. package/RAF/ahwvrz-legacy-sunset/input.md +10 -0
  4. package/RAF/ahwvrz-legacy-sunset/outcomes/01-remove-migrate-command.md +30 -0
  5. package/RAF/ahwvrz-legacy-sunset/outcomes/02-fix-resume-worktree-resolution.md +62 -0
  6. package/RAF/ahwvrz-legacy-sunset/plans/01-remove-migrate-command.md +65 -0
  7. package/RAF/ahwvrz-legacy-sunset/plans/02-fix-resume-worktree-resolution.md +72 -0
  8. package/RAF/ahwzmc-echo-forge/decisions.md +15 -0
  9. package/RAF/ahwzmc-echo-forge/input.md +4 -0
  10. package/RAF/ahwzmc-echo-forge/outcomes/01-change-low-effort-default-to-sonnet.md +57 -0
  11. package/RAF/ahwzmc-echo-forge/outcomes/02-add-no-worktree-flag.md +79 -0
  12. package/RAF/ahwzmc-echo-forge/outcomes/03-update-readme.md +75 -0
  13. package/RAF/ahwzmc-echo-forge/plans/01-change-low-effort-default-to-sonnet.md +57 -0
  14. package/RAF/ahwzmc-echo-forge/plans/02-add-no-worktree-flag.md +51 -0
  15. package/RAF/ahwzmc-echo-forge/plans/03-update-readme.md +48 -0
  16. package/RAF/aifqwf-fix-amend-commit-again/decisions.md +7 -0
  17. package/RAF/aifqwf-fix-amend-commit-again/input.md +2 -0
  18. package/RAF/aifqwf-fix-amend-commit-again/outcomes/01-update-effort-mapping-defaults.md +35 -0
  19. package/RAF/aifqwf-fix-amend-commit-again/outcomes/02-fix-amend-worktree-commit.md +50 -0
  20. package/RAF/aifqwf-fix-amend-commit-again/plans/01-update-effort-mapping-defaults.md +37 -0
  21. package/RAF/aifqwf-fix-amend-commit-again/plans/02-fix-amend-worktree-commit.md +55 -0
  22. package/README.md +26 -29
  23. package/dist/commands/do.d.ts.map +1 -1
  24. package/dist/commands/do.js +1 -0
  25. package/dist/commands/do.js.map +1 -1
  26. package/dist/commands/plan.d.ts.map +1 -1
  27. package/dist/commands/plan.js +51 -39
  28. package/dist/commands/plan.js.map +1 -1
  29. package/dist/core/git.d.ts.map +1 -1
  30. package/dist/core/git.js +20 -4
  31. package/dist/core/git.js.map +1 -1
  32. package/dist/index.js +0 -2
  33. package/dist/index.js.map +1 -1
  34. package/dist/prompts/amend.d.ts.map +1 -1
  35. package/dist/prompts/amend.js +3 -1
  36. package/dist/prompts/amend.js.map +1 -1
  37. package/dist/prompts/planning.d.ts.map +1 -1
  38. package/dist/prompts/planning.js +4 -1
  39. package/dist/prompts/planning.js.map +1 -1
  40. package/dist/types/config.d.ts +0 -4
  41. package/dist/types/config.d.ts.map +1 -1
  42. package/dist/types/config.js +2 -2
  43. package/dist/types/config.js.map +1 -1
  44. package/package.json +1 -1
  45. package/src/commands/do.ts +1 -0
  46. package/src/commands/plan.ts +54 -42
  47. package/src/core/git.ts +23 -4
  48. package/src/index.ts +0 -2
  49. package/src/prompts/amend.ts +3 -1
  50. package/src/prompts/config-docs.md +7 -7
  51. package/src/prompts/planning.ts +4 -1
  52. package/src/types/config.ts +2 -7
  53. package/tests/unit/commit-planning-artifacts-worktree.test.ts +113 -0
  54. package/tests/unit/commit-planning-artifacts.test.ts +1 -1
  55. package/tests/unit/config-command.test.ts +2 -2
  56. package/tests/unit/config.test.ts +14 -14
  57. package/tests/unit/plan-resume-worktree-resolution.test.ts +153 -0
  58. package/tests/unit/worktree-flag-override.test.ts +186 -0
  59. package/src/commands/migrate.ts +0 -269
  60. package/tests/unit/migrate-command.test.ts +0 -197
@@ -1,197 +0,0 @@
1
- import * as fs from 'node:fs';
2
- import * as path from 'node:path';
3
- import * as os from 'node:os';
4
- import { detectMigrations, type MigrationEntry } from '../../src/commands/migrate.js';
5
- import { encodeBase26 } from '../../src/utils/paths.js';
6
-
7
- describe('migrate-project-ids-base26', () => {
8
- let tempDir: string;
9
-
10
- beforeEach(() => {
11
- tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'raf-migrate-test-'));
12
- });
13
-
14
- afterEach(() => {
15
- fs.rmSync(tempDir, { recursive: true, force: true });
16
- });
17
-
18
- describe('detectMigrations', () => {
19
- it('should detect 3-char base36 legacy folders', () => {
20
- fs.mkdirSync(path.join(tempDir, '007-my-project'));
21
- fs.mkdirSync(path.join(tempDir, '01a-feature'));
22
-
23
- const migrations = detectMigrations(tempDir);
24
-
25
- expect(migrations).toHaveLength(2);
26
-
27
- // 007 in base36 = 7, encodeBase26(7) = "aaaaah"
28
- const m007 = migrations.find(m => m.oldName === '007-my-project');
29
- expect(m007).toBeDefined();
30
- expect(m007!.newName).toBe(`${encodeBase26(parseInt('007', 36))}-my-project`);
31
- expect(m007!.newName).toBe('aaaaah-my-project');
32
-
33
- // 01a in base36 = 46, encodeBase26(46) = "aaaabu"
34
- const m01a = migrations.find(m => m.oldName === '01a-feature');
35
- expect(m01a).toBeDefined();
36
- expect(m01a!.newName).toBe(`${encodeBase26(parseInt('01a', 36))}-feature`);
37
- expect(m01a!.newName).toBe('aaaabu-feature');
38
- });
39
-
40
- it('should detect 6-char base36 legacy folders with digits', () => {
41
- fs.mkdirSync(path.join(tempDir, '021h44-letterjam'));
42
- fs.mkdirSync(path.join(tempDir, '00j3k1-fix-stuff'));
43
-
44
- const migrations = detectMigrations(tempDir);
45
-
46
- expect(migrations).toHaveLength(2);
47
-
48
- const m1 = migrations.find(m => m.oldName === '021h44-letterjam');
49
- expect(m1).toBeDefined();
50
- expect(m1!.newName).toBe(`${encodeBase26(parseInt('021h44', 36))}-letterjam`);
51
-
52
- const m2 = migrations.find(m => m.oldName === '00j3k1-fix-stuff');
53
- expect(m2).toBeDefined();
54
- expect(m2!.newName).toBe(`${encodeBase26(parseInt('00j3k1', 36))}-fix-stuff`);
55
- });
56
-
57
- it('should skip already-migrated base26 folders', () => {
58
- fs.mkdirSync(path.join(tempDir, 'abcdef-my-project'));
59
- fs.mkdirSync(path.join(tempDir, 'aaaaab-another'));
60
-
61
- const migrations = detectMigrations(tempDir);
62
- expect(migrations).toHaveLength(0);
63
- });
64
-
65
- it('should skip non-directory entries', () => {
66
- fs.writeFileSync(path.join(tempDir, '007-not-a-dir'), 'file');
67
-
68
- const migrations = detectMigrations(tempDir);
69
- expect(migrations).toHaveLength(0);
70
- });
71
-
72
- it('should return empty array for non-existent directory', () => {
73
- const migrations = detectMigrations(path.join(tempDir, 'nonexistent'));
74
- expect(migrations).toHaveLength(0);
75
- });
76
-
77
- it('should return empty array when no legacy folders exist', () => {
78
- fs.mkdirSync(path.join(tempDir, 'abcdef-project'));
79
- fs.mkdirSync(path.join(tempDir, 'random-folder'));
80
-
81
- const migrations = detectMigrations(tempDir);
82
- expect(migrations).toHaveLength(0);
83
- });
84
-
85
- it('should handle mixed legacy and migrated folders', () => {
86
- fs.mkdirSync(path.join(tempDir, '007-old-project'));
87
- fs.mkdirSync(path.join(tempDir, 'abcdef-new-project'));
88
- fs.mkdirSync(path.join(tempDir, '021h44-medium-project'));
89
-
90
- const migrations = detectMigrations(tempDir);
91
- expect(migrations).toHaveLength(2);
92
- expect(migrations.map(m => m.oldName).sort()).toEqual(['007-old-project', '021h44-medium-project']);
93
- });
94
-
95
- it('should produce correct paths', () => {
96
- fs.mkdirSync(path.join(tempDir, '007-my-project'));
97
-
98
- const migrations = detectMigrations(tempDir);
99
- expect(migrations[0]!.oldPath).toBe(path.join(tempDir, '007-my-project'));
100
- expect(migrations[0]!.newPath).toBe(path.join(tempDir, 'aaaaah-my-project'));
101
- });
102
-
103
- it('should handle 3-char base36 edge cases', () => {
104
- // "000" = 0
105
- fs.mkdirSync(path.join(tempDir, '000-zero'));
106
- // "zzz" = 36^3 - 1 = 46655
107
- fs.mkdirSync(path.join(tempDir, 'zzz-max'));
108
-
109
- const migrations = detectMigrations(tempDir);
110
-
111
- // "zzz" contains no digits but matches 3-char pattern
112
- // Wait — "zzz" has no digits. The 3-char pattern is [0-9a-z]{3}
113
- // so "zzz" matches the 3-char pattern (3 chars, all lowercase letters/digits)
114
- // It gets detected as a legacy 3-char folder
115
-
116
- const m000 = migrations.find(m => m.oldName === '000-zero');
117
- expect(m000).toBeDefined();
118
- expect(m000!.newName).toBe('aaaaaa-zero');
119
-
120
- const mZzz = migrations.find(m => m.oldName === 'zzz-max');
121
- expect(mZzz).toBeDefined();
122
- expect(mZzz!.newName).toBe(`${encodeBase26(46655)}-max`);
123
- });
124
-
125
- it('should not match folders without a hyphen after the prefix', () => {
126
- fs.mkdirSync(path.join(tempDir, '007'));
127
-
128
- const migrations = detectMigrations(tempDir);
129
- expect(migrations).toHaveLength(0);
130
- });
131
-
132
- it('should handle 6-char all-letter prefix that is not pure a-z', () => {
133
- // "abcde1" has a digit, so it's legacy
134
- fs.mkdirSync(path.join(tempDir, 'abcde1-mixed'));
135
-
136
- const migrations = detectMigrations(tempDir);
137
- expect(migrations).toHaveLength(1);
138
- expect(migrations[0]!.oldName).toBe('abcde1-mixed');
139
- });
140
- });
141
-
142
- describe('migration execution (integration)', () => {
143
- it('should rename folders when executed', () => {
144
- fs.mkdirSync(path.join(tempDir, '007-my-project'));
145
- fs.writeFileSync(path.join(tempDir, '007-my-project', 'input.md'), 'test');
146
-
147
- const migrations = detectMigrations(tempDir);
148
- expect(migrations).toHaveLength(1);
149
-
150
- // Simulate what executeMigrations does
151
- const m = migrations[0]!;
152
- fs.renameSync(m.oldPath, m.newPath);
153
-
154
- // Old folder should not exist
155
- expect(fs.existsSync(path.join(tempDir, '007-my-project'))).toBe(false);
156
- // New folder should exist with contents
157
- expect(fs.existsSync(path.join(tempDir, 'aaaaah-my-project'))).toBe(true);
158
- expect(fs.readFileSync(path.join(tempDir, 'aaaaah-my-project', 'input.md'), 'utf-8')).toBe('test');
159
- });
160
-
161
- it('should preserve folder contents during rename', () => {
162
- const oldDir = path.join(tempDir, '021h44-letterjam');
163
- fs.mkdirSync(oldDir);
164
- fs.mkdirSync(path.join(oldDir, 'plans'));
165
- fs.mkdirSync(path.join(oldDir, 'outcomes'));
166
- fs.writeFileSync(path.join(oldDir, 'input.md'), 'requirements');
167
- fs.writeFileSync(path.join(oldDir, 'plans', '01-task.md'), 'plan');
168
-
169
- const migrations = detectMigrations(tempDir);
170
- const m = migrations[0]!;
171
- fs.renameSync(m.oldPath, m.newPath);
172
-
173
- expect(fs.existsSync(path.join(m.newPath, 'input.md'))).toBe(true);
174
- expect(fs.existsSync(path.join(m.newPath, 'plans', '01-task.md'))).toBe(true);
175
- expect(fs.readFileSync(path.join(m.newPath, 'input.md'), 'utf-8')).toBe('requirements');
176
- });
177
- });
178
-
179
- describe('encoding correctness', () => {
180
- it('3-char base36 IDs produce small base26 values', () => {
181
- // 007 base36 = 7
182
- expect(encodeBase26(7)).toBe('aaaaah');
183
- // 023 base36 = 75
184
- expect(encodeBase26(parseInt('023', 36))).toBe('aaaacx');
185
- // 100 base36 = 1296
186
- expect(encodeBase26(parseInt('100', 36))).toBe('aaabxw');
187
- });
188
-
189
- it('6-char base36 epoch IDs produce reasonable base26 values', () => {
190
- // These are large numbers (seconds since epoch)
191
- const val = parseInt('021h44', 36);
192
- const encoded = encodeBase26(val);
193
- expect(encoded).toHaveLength(6);
194
- expect(/^[a-z]{6}$/.test(encoded)).toBe(true);
195
- });
196
- });
197
- });