aiwf 0.3.4 → 0.3.6
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/.aiwf/00_PROJECT_MANIFEST.md +29 -16
- package/.aiwf/02_REQUIREMENTS/M03_Simone_Integration_Enhancement/M03_milestone_meta.md +55 -0
- package/.aiwf/02_REQUIREMENTS/M03_Simone_Integration_Enhancement/SPECS_AIWF_Simplified_Plan.md +221 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/S03_M02_sprint_meta.md +0 -1
- package/.aiwf/metrics/metrics.json +18 -0
- package/.aiwf/personas/current.json +5 -0
- package/.aiwf/test-results-s02.json +5 -5
- package/.claude/commands/aiwf/aiwf_add_task_to_sprint.md +283 -0
- package/.claude/commands/aiwf/aiwf_install_git_hooks.md +63 -0
- package/.claude/commands/aiwf/aiwf_link_feature_branch.md +43 -0
- package/.claude/commands/aiwf/aiwf_link_feature_commit.md +46 -0
- package/.claude/commands/aiwf/aiwf_persona_architect.md +1 -1
- package/.claude/commands/aiwf/aiwf_persona_backend.md +1 -1
- package/.claude/commands/aiwf/aiwf_persona_data_analyst.md +1 -1
- package/.claude/commands/aiwf/aiwf_persona_frontend.md +1 -1
- package/.claude/commands/aiwf/aiwf_persona_security.md +1 -1
- package/.claude/commands/aiwf/aiwf_persona_status.md +1 -1
- package/CHANGELOG.md +54 -5
- package/claude-code/aiwf/ko/commands/ai-persona.js +1 -1
- package/package.json +1 -1
- package/src/cli/index.js +58 -2
- package/src/commands/create-project.js +10 -7
- package/src/commands/persona.js +288 -0
- package/src/commands/sprint-task.js +262 -0
- package/src/lib/file-downloader.js +5 -0
- package/src/lib/installer.js +14 -4
- package/tests/integration/test-persona-system/.aiwf/metrics/metrics.json +833 -0
- package/tests/unit/sprint-task.test.js +172 -0
- package/.aiwf/sessions/session_1752877859489_1t7n2fhdb.json +0 -7
- package/.aiwf/sessions/session_1752877859515_cwdv211ry.json +0 -7
- package/.aiwf/sessions/session_1752877860664_huziadmbo.json +0 -7
- package/.aiwf/sessions/session_1752877860666_kyr5u1np6.json +0 -7
- package/.aiwf/sessions/session_1752877861848_9yinepw3t.json +0 -7
- package/.aiwf/sessions/session_1752877861874_y32sputuc.json +0 -7
- package/.aiwf/sessions/session_1752877862685_ivxbl5rhz.json +0 -7
- package/.aiwf/sessions/session_1752877862820_wnq4glvxi.json +0 -7
- package/.aiwf/sessions/session_1752877864632_3ebnpaelb.json +0 -7
- package/.aiwf/sessions/session_1752877864879_b9zgjcb7d.json +0 -7
- package/.aiwf/sessions/session_1752877865533_x14m1vodi.json +0 -7
- package/.aiwf/sessions/session_1752877865562_gkoh19n7d.json +0 -7
- package/.aiwf/sessions/session_1752877866333_wp8qpdcoh.json +0 -7
- package/.aiwf/sessions/session_1752877866509_dawntfpab.json +0 -7
- package/.aiwf/sessions/session_1752877866890_plc5vfucl.json +0 -7
- package/.aiwf/sessions/session_1752877866895_ga8hmq3oi.json +0 -7
- package/.aiwf/sessions/session_1752877867761_ayjp4v5f5.json +0 -7
- package/.aiwf/sessions/session_1752877867892_lfz6jy252.json +0 -7
- package/.aiwf/sessions/session_1752877868139_7bqd9ubli.json +0 -7
- package/.aiwf/sessions/session_1752877868162_zq3ofjbsh.json +0 -7
- package/.aiwf/sessions/session_1752877869054_7rlgm9jt6.json +0 -7
- package/.aiwf/sessions/session_1752877869477_ax3nhbxzr.json +0 -7
- package/.aiwf/sessions/session_1752877870095_6hgp4vl1e.json +0 -7
- package/.aiwf/sessions/session_1752877870381_qfcrdg4li.json +0 -7
- package/.aiwf/sessions/session_1752877871895_pgd5vllhz.json +0 -7
- package/.aiwf/sessions/session_1752877872199_jbhv2g2da.json +0 -7
- package/.aiwf/sessions/session_1752877872680_x04wpffu6.json +0 -7
- package/.aiwf/sessions/session_1752877872895_3y4vbeauo.json +0 -7
- package/.aiwf/sessions/session_1752877873178_3maolzc6b.json +0 -7
- package/.aiwf/sessions/session_1752877873180_ytm83j07f.json +0 -7
- package/.aiwf/sessions/session_1752877874217_dp56c9t42.json +0 -7
- package/.aiwf/sessions/session_1752877874415_epwp1g1og.json +0 -7
- package/.aiwf/sessions/session_1752877874454_heicyuryb.json +0 -7
- package/.aiwf/sessions/session_1752877874869_1c2illeu5.json +0 -7
- package/.aiwf/sessions/session_1752877874879_k1vo4vxyx.json +0 -7
- package/.aiwf/sessions/session_1752877874913_bwgyiz9bp.json +0 -7
- package/.aiwf/sessions/session_1752877876218_44807kztz.json +0 -7
- package/.aiwf/sessions/session_1752877876515_qkhjv5kpw.json +0 -7
- package/.aiwf/sessions/session_1752877876543_p605aud1m.json +0 -7
- package/.aiwf/sessions/session_1752877876819_l65w7ifck.json +0 -7
- package/.aiwf/sessions/session_1752877876867_xrhzss4we.json +0 -7
- package/.aiwf/sessions/session_1752877876872_u7aso54qb.json +0 -7
- package/.aiwf/sessions/session_1752877877705_telnfg4o6.json +0 -7
- package/.aiwf/sessions/session_1752877878285_6s45im2ib.json +0 -7
- package/.aiwf/sessions/session_1752877878506_v0dvguqhz.json +0 -7
- package/.aiwf/sessions/session_1752877878581_3ri3yc66a.json +0 -7
- package/.aiwf/sessions/session_1752877878756_a82x9s2pd.json +0 -7
- package/.aiwf/sessions/session_1752877878886_20pjsfour.json +0 -7
- package/.aiwf/sessions/session_1752877880266_fm1ydjw0g.json +0 -7
- package/.aiwf/sessions/session_1752877881149_xbat4z03d.json +0 -7
- package/.aiwf/sessions/session_1752877881551_qy5sic9qs.json +0 -7
- package/.aiwf/sessions/session_1752877881554_24ugd96wu.json +0 -7
- package/.aiwf/sessions/session_1752877881797_e9mm25uh0.json +0 -7
- package/.aiwf/sessions/session_1752877881822_bxvjj8c9g.json +0 -7
- package/.aiwf/sessions/session_1752877881890_jv7l6jve3.json +0 -7
- package/.aiwf/sessions/session_1752877881991_f0qugdtcq.json +0 -7
- package/.aiwf/sessions/session_1752877883387_0bvw9rvnx.json +0 -7
- package/.aiwf/sessions/session_1752877883820_q6g2md2up.json +0 -7
- package/.aiwf/sessions/session_1752877884393_sqr7trvjl.json +0 -7
- package/.aiwf/sessions/session_1752877884500_whtypmzlf.json +0 -7
- package/.aiwf/sessions/session_1752877884645_y9mvvxli1.json +0 -7
- package/.aiwf/sessions/session_1752877884733_hk46eenel.json +0 -7
- package/.aiwf/sessions/session_1752877884738_c62j6214r.json +0 -7
- package/.aiwf/sessions/session_1752877884771_temhxehoz.json +0 -7
- package/.aiwf/sessions/session_1752877885643_6v5fcktc7.json +0 -7
- package/.aiwf/sessions/session_1752877886426_ee8di2fqh.json +0 -7
- package/.aiwf/sessions/session_1752877886549_3xj6tdoew.json +0 -7
- package/.aiwf/sessions/session_1752877886604_aj80yyfco.json +0 -7
- package/.aiwf/sessions/session_1752877886702_2b8841vyg.json +0 -7
- package/.aiwf/sessions/session_1752877886712_ntqc8b8bz.json +0 -7
- package/.aiwf/sessions/session_1752877886968_946m8tbw6.json +0 -7
- package/.aiwf/sessions/session_1752877887008_wg6zfg8dn.json +0 -7
- package/.aiwf/sessions/session_1752877888479_ciiu2qiqs.json +0 -7
- package/.aiwf/sessions/session_1752877889330_ravg8l66k.json +0 -7
- package/.aiwf/sessions/session_1752877889542_7zepkhjkc.json +0 -7
- package/.aiwf/sessions/session_1752877889638_ev4htqiu0.json +0 -7
- package/.aiwf/sessions/session_1752877889956_szphy2qma.json +0 -7
- package/.aiwf/sessions/session_1752877890220_o6aaa57tt.json +0 -7
- package/.aiwf/sessions/session_1752877890527_v2loy5vu1.json +0 -7
- package/.aiwf/sessions/session_1752877890572_cwq8fiuma.json +0 -7
- package/.aiwf/sessions/session_1752877892200_sgcwq1alt.json +0 -7
- package/.aiwf/sessions/session_1752877892268_v8kexpbc5.json +0 -7
- package/.aiwf/sessions/session_1752877892384_1gbbgrp4y.json +0 -7
- package/.aiwf/sessions/session_1752877893568_9p2n5p31a.json +0 -7
- package/.aiwf/sessions/session_1752877893727_un34a5tvp.json +0 -7
- package/.aiwf/sessions/session_1752877893778_01j79sw9i.json +0 -7
- package/.aiwf/sessions/session_1752877894053_jrhba6wko.json +0 -7
- package/.aiwf/sessions/session_1752877894082_x3bghawox.json +0 -7
- package/.aiwf/sessions/session_1752877894500_iytiav2ku.json +0 -7
- package/.aiwf/sessions/session_1752877894667_ucn0gc2ge.json +0 -7
- package/test-token-system.js +0 -88
- package/tests/temp_invalid_json/invalid.json +0 -1
- /package/{.aiwf/templates → templates}/README.md +0 -0
- /package/{.aiwf/templates → templates}/api-server/config.json +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/.aiwf/config.json +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/.aiwf/feature-ledger.json +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/.aiwf/personas/backend-engineer.json +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/.aiwf/scripts/cli.js +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/.env.example +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/.eslintrc.json +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/README.md +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/jest.config.js +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/nodemon.json +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/package.json +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/src/app.ts +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/src/config/swagger.ts +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/src/controllers/aiwfController.ts +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/src/controllers/authController.ts +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/src/controllers/statusController.ts +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/src/index.ts +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/src/middleware/aiwfMiddleware.ts +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/src/middleware/authMiddleware.ts +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/src/middleware/errorHandler.ts +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/src/middleware/notFoundHandler.ts +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/src/middleware/requestLogger.ts +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/src/routes/aiwf.ts +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/src/routes/index.ts +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/src/routes/v1/index.ts +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/src/utils/logger.ts +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/tests/app.test.ts +0 -0
- /package/{.aiwf/templates → templates}/api-server/template/tsconfig.json +0 -0
- /package/{.aiwf/templates → templates}/npm-library/config.json +0 -0
- /package/{.aiwf/templates → templates}/npm-library/template/LICENSE +0 -0
- /package/{.aiwf/templates → templates}/npm-library/template/README.md +0 -0
- /package/{.aiwf/templates → templates}/npm-library/template/package.json +0 -0
- /package/{.aiwf/templates → templates}/web-app/config.json +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/.aiwf/config.json +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/.aiwf/feature-ledger.json +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/.aiwf/personas/fullstack-developer.json +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/.aiwf/scripts/cli.js +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/.eslintrc.cjs +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/README.md +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/index.html +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/package.json +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/postcss.config.js +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/public/vite.svg +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/src/App.tsx +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/src/components/Layout.tsx +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/src/components/aiwf/ContextStatus.tsx +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/src/components/aiwf/FeatureLedger.tsx +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/src/components/aiwf/TokenUsage.tsx +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/src/index.css +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/src/main.tsx +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/src/pages/AiwfDashboard.tsx +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/src/pages/HomePage.tsx +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/src/pages/NotFound.tsx +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/src/stores/aiwfStore.ts +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/src/types/global.d.ts +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/src/vite-env.d.ts +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/tailwind.config.js +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/tsconfig.json +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/tsconfig.node.json +0 -0
- /package/{.aiwf/templates → templates}/web-app/template/vite.config.ts +0 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 스프린트 태스크 관리 테스트
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { jest } from '@jest/globals';
|
|
6
|
+
import { addTaskToSprint } from '../../src/commands/sprint-task.js';
|
|
7
|
+
|
|
8
|
+
// Manual mocks
|
|
9
|
+
const mockFs = {
|
|
10
|
+
access: jest.fn(),
|
|
11
|
+
readdir: jest.fn(),
|
|
12
|
+
readFile: jest.fn(),
|
|
13
|
+
writeFile: jest.fn()
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// Mock the fs/promises module
|
|
17
|
+
jest.unstable_mockModule('fs/promises', () => mockFs);
|
|
18
|
+
|
|
19
|
+
describe('Sprint Task Management', () => {
|
|
20
|
+
const mockProjectRoot = '/test/project';
|
|
21
|
+
const mockSprintPath = '/test/project/.aiwf/03_SPRINTS/S03_M02_test_sprint';
|
|
22
|
+
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
jest.clearAllMocks();
|
|
25
|
+
|
|
26
|
+
// Mock console methods
|
|
27
|
+
global.console.log = jest.fn();
|
|
28
|
+
global.console.warn = jest.fn();
|
|
29
|
+
global.console.error = jest.fn();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('addTaskToSprint', () => {
|
|
33
|
+
it('should successfully add a task to an existing sprint', async () => {
|
|
34
|
+
// Mock file system operations
|
|
35
|
+
mockFs.access.mockResolvedValue();
|
|
36
|
+
mockFs.readdir
|
|
37
|
+
.mockResolvedValueOnce(['.aiwf']) // Project root check
|
|
38
|
+
.mockResolvedValueOnce(['S01_M01_sprint1', 'S03_M02_test_sprint']) // Sprint directory
|
|
39
|
+
.mockResolvedValueOnce(['T01_S03_existing_task.md', 'S03_sprint_meta.md']); // Sprint contents
|
|
40
|
+
|
|
41
|
+
mockFs.readFile.mockResolvedValueOnce(`# S03 Sprint Meta
|
|
42
|
+
## 태스크 목록
|
|
43
|
+
- [ ] T01: Existing Task - 상태: pending
|
|
44
|
+
`);
|
|
45
|
+
|
|
46
|
+
mockFs.writeFile.mockResolvedValue();
|
|
47
|
+
|
|
48
|
+
// Execute
|
|
49
|
+
const result = await addTaskToSprint('S03', 'New Test Task');
|
|
50
|
+
|
|
51
|
+
// Verify
|
|
52
|
+
expect(result.success).toBe(true);
|
|
53
|
+
expect(result.taskNumber).toBe('T02');
|
|
54
|
+
expect(mockFs.writeFile).toHaveBeenCalledTimes(3); // Task file, sprint meta, manifest
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should handle first task in sprint correctly', async () => {
|
|
58
|
+
// Mock empty sprint
|
|
59
|
+
mockFs.access.mockResolvedValue();
|
|
60
|
+
mockFs.readdir
|
|
61
|
+
.mockResolvedValueOnce(['.aiwf'])
|
|
62
|
+
.mockResolvedValueOnce(['S03_M02_test_sprint'])
|
|
63
|
+
.mockResolvedValueOnce(['S03_sprint_meta.md']); // No task files
|
|
64
|
+
|
|
65
|
+
mockFs.readFile.mockResolvedValueOnce(`# S03 Sprint Meta
|
|
66
|
+
## 개요
|
|
67
|
+
Test sprint
|
|
68
|
+
`);
|
|
69
|
+
|
|
70
|
+
mockFs.writeFile.mockResolvedValue();
|
|
71
|
+
|
|
72
|
+
const result = await addTaskToSprint('S03', 'First Task');
|
|
73
|
+
|
|
74
|
+
expect(result.taskNumber).toBe('T01');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should throw error when sprint does not exist', async () => {
|
|
78
|
+
mockFs.access.mockResolvedValue();
|
|
79
|
+
mockFs.readdir
|
|
80
|
+
.mockResolvedValueOnce(['.aiwf'])
|
|
81
|
+
.mockResolvedValueOnce(['S01_M01_sprint1']); // S03 not found
|
|
82
|
+
|
|
83
|
+
await expect(addTaskToSprint('S03', 'Test Task'))
|
|
84
|
+
.rejects.toThrow('스프린트 S03를 찾을 수 없습니다.');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should sanitize task title for filename', async () => {
|
|
88
|
+
mockFs.access.mockResolvedValue();
|
|
89
|
+
mockFs.readdir
|
|
90
|
+
.mockResolvedValueOnce(['.aiwf'])
|
|
91
|
+
.mockResolvedValueOnce(['S03_M02_test_sprint'])
|
|
92
|
+
.mockResolvedValueOnce([]);
|
|
93
|
+
|
|
94
|
+
mockFs.readFile.mockResolvedValueOnce('# Sprint Meta');
|
|
95
|
+
mockFs.writeFile.mockResolvedValue();
|
|
96
|
+
|
|
97
|
+
await addTaskToSprint('S03', 'Task with Special!@# Characters');
|
|
98
|
+
|
|
99
|
+
// Check that the filename was sanitized
|
|
100
|
+
const writeCall = mockFs.writeFile.mock.calls[0];
|
|
101
|
+
const filePath = writeCall[0];
|
|
102
|
+
expect(filePath).toMatch(/T01_S03_task_with_special_characters\.md$/);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
describe('Error Handling', () => {
|
|
107
|
+
it('should handle missing .aiwf directory', async () => {
|
|
108
|
+
mockFs.access.mockRejectedValue(new Error('Not found'));
|
|
109
|
+
|
|
110
|
+
await expect(addTaskToSprint('S03', 'Test'))
|
|
111
|
+
.rejects.toThrow('.aiwf 디렉토리를 찾을 수 없습니다');
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('should warn when sprint meta file is missing', async () => {
|
|
115
|
+
mockFs.access.mockResolvedValue();
|
|
116
|
+
mockFs.readdir
|
|
117
|
+
.mockResolvedValueOnce(['.aiwf'])
|
|
118
|
+
.mockResolvedValueOnce(['S03_M02_test_sprint'])
|
|
119
|
+
.mockResolvedValueOnce([]); // No meta file
|
|
120
|
+
|
|
121
|
+
mockFs.writeFile.mockResolvedValue();
|
|
122
|
+
|
|
123
|
+
await addTaskToSprint('S03', 'Test Task');
|
|
124
|
+
|
|
125
|
+
expect(console.warn).toHaveBeenCalledWith(
|
|
126
|
+
expect.stringContaining('스프린트 메타 파일을 찾을 수 없습니다')
|
|
127
|
+
);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
describe('Task Numbering', () => {
|
|
132
|
+
it('should correctly determine next task number', async () => {
|
|
133
|
+
mockFs.access.mockResolvedValue();
|
|
134
|
+
mockFs.readdir
|
|
135
|
+
.mockResolvedValueOnce(['.aiwf'])
|
|
136
|
+
.mockResolvedValueOnce(['S03_M02_test_sprint'])
|
|
137
|
+
.mockResolvedValueOnce([
|
|
138
|
+
'T01_S03_task1.md',
|
|
139
|
+
'T03_S03_task3.md',
|
|
140
|
+
'T10_S03_task10.md',
|
|
141
|
+
'S03_sprint_meta.md'
|
|
142
|
+
]);
|
|
143
|
+
|
|
144
|
+
mockFs.readFile.mockResolvedValueOnce('# Sprint Meta');
|
|
145
|
+
mockFs.writeFile.mockResolvedValue();
|
|
146
|
+
|
|
147
|
+
const result = await addTaskToSprint('S03', 'Next Task');
|
|
148
|
+
|
|
149
|
+
expect(result.taskNumber).toBe('T11'); // Next after T10
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('should handle non-standard task filenames', async () => {
|
|
153
|
+
mockFs.access.mockResolvedValue();
|
|
154
|
+
mockFs.readdir
|
|
155
|
+
.mockResolvedValueOnce(['.aiwf'])
|
|
156
|
+
.mockResolvedValueOnce(['S03_M02_test_sprint'])
|
|
157
|
+
.mockResolvedValueOnce([
|
|
158
|
+
'T01_S03_task1.md',
|
|
159
|
+
'random_file.txt',
|
|
160
|
+
'TX05_not_a_task.md',
|
|
161
|
+
'S03_sprint_meta.md'
|
|
162
|
+
]);
|
|
163
|
+
|
|
164
|
+
mockFs.readFile.mockResolvedValueOnce('# Sprint Meta');
|
|
165
|
+
mockFs.writeFile.mockResolvedValue();
|
|
166
|
+
|
|
167
|
+
const result = await addTaskToSprint('S03', 'Next Task');
|
|
168
|
+
|
|
169
|
+
expect(result.taskNumber).toBe('T02'); // Only counts valid task files
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
});
|