@kosuke-ai/cli 0.0.38 ā 0.0.40
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/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +109 -51
- package/dist/index.js.map +1 -1
- package/dist/kosuke/commands/build.d.ts.map +1 -1
- package/dist/kosuke/commands/build.js +171 -54
- package/dist/kosuke/commands/build.js.map +1 -1
- package/dist/kosuke/commands/migrate.d.ts +33 -0
- package/dist/kosuke/commands/migrate.d.ts.map +1 -0
- package/dist/kosuke/commands/migrate.js +196 -0
- package/dist/kosuke/commands/migrate.js.map +1 -0
- package/dist/kosuke/commands/ship.d.ts.map +1 -1
- package/dist/kosuke/commands/ship.js +4 -9
- package/dist/kosuke/commands/ship.js.map +1 -1
- package/dist/kosuke/commands/test.d.ts +18 -9
- package/dist/kosuke/commands/test.d.ts.map +1 -1
- package/dist/kosuke/commands/test.js +48 -68
- package/dist/kosuke/commands/test.js.map +1 -1
- package/dist/kosuke/commands/tickets.d.ts +24 -13
- package/dist/kosuke/commands/tickets.d.ts.map +1 -1
- package/dist/kosuke/commands/tickets.js +339 -353
- package/dist/kosuke/commands/tickets.js.map +1 -1
- package/dist/kosuke/types.d.ts +35 -5
- package/dist/kosuke/types.d.ts.map +1 -1
- package/dist/kosuke/utils/logger.d.ts +1 -1
- package/dist/kosuke/utils/logger.d.ts.map +1 -1
- package/dist/kosuke/utils/prompt-generator.d.ts +2 -2
- package/dist/kosuke/utils/prompt-generator.d.ts.map +1 -1
- package/dist/kosuke/utils/prompt-generator.js +2 -2
- package/dist/kosuke/utils/prompt-generator.js.map +1 -1
- package/dist/kosuke/utils/test-runner.d.ts.map +1 -1
- package/dist/kosuke/utils/test-runner.js +9 -2
- package/dist/kosuke/utils/test-runner.js.map +1 -1
- package/dist/kosuke/utils/tickets-manager.d.ts +0 -4
- package/dist/kosuke/utils/tickets-manager.d.ts.map +1 -1
- package/dist/kosuke/utils/tickets-manager.js +1 -1
- package/dist/kosuke/utils/tickets-manager.js.map +1 -1
- package/dist/lib.d.ts +2 -1
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +1 -0
- package/dist/lib.js.map +1 -1
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -10,8 +10,9 @@
|
|
|
10
10
|
* getcode Explore GitHub repositories and fetch code
|
|
11
11
|
* tickets Generate implementation tickets from requirements
|
|
12
12
|
* build Batch process all tickets from tickets.json
|
|
13
|
+
* migrate Apply database migrations and validate schema
|
|
13
14
|
* review Review codebase against CLAUDE.md rules
|
|
14
|
-
* test Run E2E tests
|
|
15
|
+
* test Run atomic web E2E tests
|
|
15
16
|
*
|
|
16
17
|
* Usage:
|
|
17
18
|
* bun run kosuke sync-rules
|
|
@@ -21,8 +22,9 @@
|
|
|
21
22
|
* bun run kosuke getcode "query"
|
|
22
23
|
* bun run kosuke tickets
|
|
23
24
|
* bun run kosuke build
|
|
25
|
+
* bun run kosuke migrate
|
|
24
26
|
* bun run kosuke review
|
|
25
|
-
* bun run kosuke test --
|
|
27
|
+
* bun run kosuke test --prompt="Test user login flow"
|
|
26
28
|
*
|
|
27
29
|
* Environment Variables:
|
|
28
30
|
* ANTHROPIC_API_KEY - Required for Claude API
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";AAEA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,eAAe,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -10,8 +10,9 @@
|
|
|
10
10
|
* getcode Explore GitHub repositories and fetch code
|
|
11
11
|
* tickets Generate implementation tickets from requirements
|
|
12
12
|
* build Batch process all tickets from tickets.json
|
|
13
|
+
* migrate Apply database migrations and validate schema
|
|
13
14
|
* review Review codebase against CLAUDE.md rules
|
|
14
|
-
* test Run E2E tests
|
|
15
|
+
* test Run atomic web E2E tests
|
|
15
16
|
*
|
|
16
17
|
* Usage:
|
|
17
18
|
* bun run kosuke sync-rules
|
|
@@ -21,8 +22,9 @@
|
|
|
21
22
|
* bun run kosuke getcode "query"
|
|
22
23
|
* bun run kosuke tickets
|
|
23
24
|
* bun run kosuke build
|
|
25
|
+
* bun run kosuke migrate
|
|
24
26
|
* bun run kosuke review
|
|
25
|
-
* bun run kosuke test --
|
|
27
|
+
* bun run kosuke test --prompt="Test user login flow"
|
|
26
28
|
*
|
|
27
29
|
* Environment Variables:
|
|
28
30
|
* ANTHROPIC_API_KEY - Required for Claude API
|
|
@@ -33,6 +35,7 @@ import { analyseCommand } from './kosuke/commands/analyse.js';
|
|
|
33
35
|
import { buildCommand } from './kosuke/commands/build.js';
|
|
34
36
|
import { getCodeCommand, parseGetCodeArgs } from './kosuke/commands/getcode.js';
|
|
35
37
|
import { lintCommand } from './kosuke/commands/lint.js';
|
|
38
|
+
import { migrateCommand } from './kosuke/commands/migrate.js';
|
|
36
39
|
import { requirementsCommand } from './kosuke/commands/requirements.js';
|
|
37
40
|
import { reviewCommand } from './kosuke/commands/review.js';
|
|
38
41
|
import { syncRulesCommand } from './kosuke/commands/sync-rules.js';
|
|
@@ -96,6 +99,8 @@ async function main() {
|
|
|
96
99
|
output: args.find((arg) => arg.startsWith('--output='))?.split('=')[1],
|
|
97
100
|
directory: args.find((arg) => arg.startsWith('--directory='))?.split('=')[1] ||
|
|
98
101
|
args.find((arg) => arg.startsWith('--dir='))?.split('=')[1],
|
|
102
|
+
scaffold: args.includes('--scaffold'),
|
|
103
|
+
prompt: args.find((arg) => arg.startsWith('--prompt='))?.split('=')[1],
|
|
99
104
|
noLogs: args.includes('--no-logs'),
|
|
100
105
|
};
|
|
101
106
|
await ticketsCommand(options);
|
|
@@ -120,6 +125,16 @@ async function main() {
|
|
|
120
125
|
await buildCommand(options);
|
|
121
126
|
break;
|
|
122
127
|
}
|
|
128
|
+
case 'migrate': {
|
|
129
|
+
const options = {
|
|
130
|
+
directory: args.find((arg) => arg.startsWith('--directory='))?.split('=')[1] ||
|
|
131
|
+
args.find((arg) => arg.startsWith('--dir='))?.split('=')[1],
|
|
132
|
+
dbUrl: args.find((arg) => arg.startsWith('--db-url='))?.split('=')[1],
|
|
133
|
+
noLogs: args.includes('--no-logs'),
|
|
134
|
+
};
|
|
135
|
+
await migrateCommand(options);
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
123
138
|
case 'review': {
|
|
124
139
|
const options = {
|
|
125
140
|
noLogs: args.includes('--no-logs'),
|
|
@@ -128,36 +143,28 @@ async function main() {
|
|
|
128
143
|
break;
|
|
129
144
|
}
|
|
130
145
|
case 'test': {
|
|
131
|
-
const ticketArg = args.find((arg) => arg.startsWith('--ticket='))?.split('=')[1];
|
|
132
146
|
const promptArg = args.find((arg) => arg.startsWith('--prompt='))?.split('=')[1];
|
|
133
|
-
if (!
|
|
134
|
-
console.error('ā
|
|
135
|
-
console.log('Usage: kosuke test --
|
|
147
|
+
if (!promptArg) {
|
|
148
|
+
console.error('ā The --prompt flag is required\n');
|
|
149
|
+
console.log('Usage: kosuke test --prompt="..." [OPTIONS]');
|
|
136
150
|
console.log('\nOptions:');
|
|
137
|
-
console.log(' --
|
|
138
|
-
console.log(' --
|
|
139
|
-
console.log(' --
|
|
140
|
-
console.log(' --
|
|
141
|
-
console.log(' --
|
|
142
|
-
console.log(' --directory=PATH Directory to test (default: cwd)');
|
|
151
|
+
console.log(' --prompt="..." Test instructions (required)');
|
|
152
|
+
console.log(' --url=URL Base URL for web tests (default: http://localhost:3000)');
|
|
153
|
+
console.log(' --headless Run in headless mode (invisible browser)');
|
|
154
|
+
console.log(' --verbose Enable verbose output');
|
|
155
|
+
console.log(' --directory=PATH Directory to test (default: cwd)');
|
|
143
156
|
console.log('\nExamples:');
|
|
144
|
-
console.log(' kosuke test --
|
|
145
|
-
console.log(' kosuke test --prompt="Test
|
|
146
|
-
console.log('
|
|
147
|
-
console.log('
|
|
148
|
-
process.exit(1);
|
|
149
|
-
}
|
|
150
|
-
if (ticketArg && promptArg) {
|
|
151
|
-
console.error('ā Cannot provide both --ticket and --prompt. Use one or the other.\n');
|
|
157
|
+
console.log(' kosuke test --prompt="Test user login flow"');
|
|
158
|
+
console.log(' kosuke test --prompt="Test task creation" --verbose --headless');
|
|
159
|
+
console.log('\nNote: This command is mainly used programmatically from kosuke build.');
|
|
160
|
+
console.log(' For ticket-based testing with retries, use: kosuke build');
|
|
152
161
|
process.exit(1);
|
|
153
162
|
}
|
|
154
163
|
const options = {
|
|
155
|
-
ticket: ticketArg,
|
|
156
164
|
prompt: promptArg,
|
|
157
165
|
url: args.find((arg) => arg.startsWith('--url='))?.split('=')[1],
|
|
158
166
|
headless: args.includes('--headless'),
|
|
159
167
|
verbose: args.includes('--verbose'),
|
|
160
|
-
ticketsFile: args.find((arg) => arg.startsWith('--tickets='))?.split('=')[1],
|
|
161
168
|
directory: args.find((arg) => arg.startsWith('--directory='))?.split('=')[1] ||
|
|
162
169
|
args.find((arg) => arg.startsWith('--dir='))?.split('=')[1],
|
|
163
170
|
noLogs: args.includes('--no-logs'),
|
|
@@ -252,29 +259,61 @@ COMMANDS:
|
|
|
252
259
|
kosuke getcode -t "Show me pagination examples"
|
|
253
260
|
|
|
254
261
|
tickets [options]
|
|
255
|
-
Generate implementation tickets from requirements document
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
262
|
+
Generate implementation tickets from requirements document or inline prompt
|
|
263
|
+
Intelligently determines which layers (schema/backend/frontend) are needed
|
|
264
|
+
|
|
265
|
+
LOGIC-ONLY MODE (default - for existing projects):
|
|
266
|
+
Analyzes requirements and generates only needed tickets:
|
|
267
|
+
- Schema logic (if database changes needed)
|
|
268
|
+
- Backend logic (if API changes needed)
|
|
269
|
+
- Frontend logic (if UI changes needed)
|
|
270
|
+
- DB tests (if schema changes)
|
|
271
|
+
- Web tests (if implementation changes)
|
|
272
|
+
|
|
273
|
+
SCAFFOLD MODE (--scaffold flag - for new projects):
|
|
274
|
+
Generates full infrastructure setup + business logic:
|
|
275
|
+
|
|
276
|
+
SCAFFOLD BATCH:
|
|
277
|
+
1. Schema scaffold (auth, billing, infrastructure)
|
|
278
|
+
2. DB test (validate scaffold)
|
|
279
|
+
3. Backend scaffold (API infrastructure)
|
|
280
|
+
4. Frontend scaffold (UI infrastructure)
|
|
281
|
+
5. Web tests (validate scaffold E2E)
|
|
282
|
+
|
|
283
|
+
LOGIC BATCH:
|
|
284
|
+
1. Schema logic (business entities)
|
|
285
|
+
2. DB test (validate logic)
|
|
286
|
+
3. Backend logic (business API)
|
|
287
|
+
4. Frontend logic (business UI)
|
|
288
|
+
5. Web tests (validate logic E2E)
|
|
260
289
|
|
|
261
290
|
Options:
|
|
262
|
-
--path=<file> Path to requirements document (default: docs.md
|
|
263
|
-
--
|
|
291
|
+
--path=<file> Path to requirements document (default: docs.md)
|
|
292
|
+
--prompt="..." Inline requirements (alternative to --path)
|
|
293
|
+
--scaffold Enable scaffold mode for new projects
|
|
294
|
+
--output=<file> Output file for tickets (default: tickets.json)
|
|
264
295
|
--directory=<path> Directory for Claude to explore (default: current directory)
|
|
265
296
|
--dir=<path> Alias for --directory
|
|
266
297
|
|
|
267
298
|
Examples:
|
|
268
|
-
|
|
269
|
-
kosuke tickets --
|
|
270
|
-
kosuke tickets --
|
|
271
|
-
kosuke tickets --
|
|
272
|
-
|
|
299
|
+
# Logic-only mode (existing projects)
|
|
300
|
+
kosuke tickets --prompt="Add dark mode toggle"
|
|
301
|
+
kosuke tickets --prompt="Add user notifications"
|
|
302
|
+
kosuke tickets --path=feature.md
|
|
303
|
+
|
|
304
|
+
# Scaffold mode (new projects)
|
|
305
|
+
kosuke tickets --scaffold --path=docs.md
|
|
306
|
+
kosuke tickets --scaffold --prompt="Build a task manager with teams"
|
|
307
|
+
|
|
308
|
+
# With custom options
|
|
309
|
+
kosuke tickets --directory=./my-app --prompt="Add export to CSV"
|
|
310
|
+
kosuke tickets --output=my-tickets.json --path=requirements.md
|
|
273
311
|
|
|
274
312
|
build [options]
|
|
275
313
|
Batch process all "Todo" and "Error" tickets from tickets.json
|
|
276
|
-
Implements and
|
|
277
|
-
Processes tickets in order: Schema ā Backend ā Frontend
|
|
314
|
+
Implements tickets and runs tests with automatic fixing
|
|
315
|
+
Processes tickets in order: Schema (auto-validated) ā Backend ā Frontend ā Web Test
|
|
316
|
+
Commits in batches after each web-test completion
|
|
278
317
|
Frontend tickets automatically include E2E testing (unless --no-test)
|
|
279
318
|
All tickets include code review by default (unless --no-review)
|
|
280
319
|
|
|
@@ -310,6 +349,23 @@ COMMANDS:
|
|
|
310
349
|
|
|
311
350
|
Note: If a ticket fails, fix the issue and run build again to resume
|
|
312
351
|
|
|
352
|
+
migrate [options]
|
|
353
|
+
Apply database migrations and validate schema changes
|
|
354
|
+
Uses Claude Code Agent to run migrations, seed database, and validate
|
|
355
|
+
|
|
356
|
+
Note: This command does NOT generate migrations (ship handles that)
|
|
357
|
+
Automatically called by build command after SCHEMA tickets
|
|
358
|
+
|
|
359
|
+
Options:
|
|
360
|
+
--directory=<path> Directory to run migrations in (default: current directory)
|
|
361
|
+
--dir=<path> Alias for --directory
|
|
362
|
+
--db-url=<url> Database URL (default: postgres://postgres:postgres@localhost:5432/postgres)
|
|
363
|
+
|
|
364
|
+
Examples:
|
|
365
|
+
kosuke migrate # Apply migrations in current directory
|
|
366
|
+
kosuke migrate --directory=./my-app # Apply in specific project
|
|
367
|
+
kosuke migrate --db-url=postgres://... # Custom database URL
|
|
368
|
+
|
|
313
369
|
review
|
|
314
370
|
Review current git diff against CLAUDE.md rules
|
|
315
371
|
Identifies and fixes compliance issues in uncommitted changes
|
|
@@ -318,28 +374,30 @@ COMMANDS:
|
|
|
318
374
|
Examples:
|
|
319
375
|
kosuke review # Review uncommitted changes
|
|
320
376
|
|
|
321
|
-
test
|
|
322
|
-
Run atomic
|
|
323
|
-
|
|
324
|
-
|
|
377
|
+
test --prompt="..." [options]
|
|
378
|
+
Run atomic web E2E tests (no fixing, no retries)
|
|
379
|
+
|
|
380
|
+
Test type:
|
|
381
|
+
- web-test: Browser E2E testing with Stagehand + Claude AI
|
|
382
|
+
|
|
383
|
+
For iterative test+fix workflow, use: kosuke build
|
|
325
384
|
|
|
326
385
|
Options:
|
|
327
|
-
--
|
|
328
|
-
--
|
|
329
|
-
--
|
|
330
|
-
--headless Run in headless mode (invisible browser)
|
|
386
|
+
--prompt="..." Test instructions (required)
|
|
387
|
+
--url=<URL> Base URL for web tests (default: http://localhost:3000)
|
|
388
|
+
--headless Run browser in headless mode (invisible)
|
|
331
389
|
--verbose Enable verbose output
|
|
332
|
-
--tickets=<file> Path to tickets file (default: tickets.json, relative to directory)
|
|
333
390
|
--directory=<path> Directory to run tests in (default: current directory)
|
|
334
391
|
--dir=<path> Alias for --directory
|
|
335
392
|
|
|
336
393
|
Examples:
|
|
337
|
-
kosuke test --
|
|
338
|
-
kosuke test --prompt="Test
|
|
339
|
-
kosuke test --
|
|
340
|
-
kosuke test --prompt="..." --
|
|
341
|
-
|
|
342
|
-
|
|
394
|
+
kosuke test --prompt="Test user login flow"
|
|
395
|
+
kosuke test --prompt="Test task creation" --url=http://localhost:4000
|
|
396
|
+
kosuke test --prompt="..." --verbose --headless
|
|
397
|
+
kosuke test --prompt="..." --directory=./my-project
|
|
398
|
+
|
|
399
|
+
Note: This command is mainly used programmatically from kosuke build.
|
|
400
|
+
For ticket-based testing with retries, use: kosuke build
|
|
343
401
|
|
|
344
402
|
GLOBAL OPTIONS:
|
|
345
403
|
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";AAEA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../kosuke/commands/build.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAU,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../kosuke/commands/build.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAU,MAAM,aAAa,CAAC;AAmGxD;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAqTvE"}
|
|
@@ -27,9 +27,11 @@ import { existsSync, statSync } from 'fs';
|
|
|
27
27
|
import { join, resolve } from 'path';
|
|
28
28
|
import * as readline from 'readline';
|
|
29
29
|
import simpleGit from 'simple-git';
|
|
30
|
-
import {
|
|
30
|
+
import { generateWebTestPrompt } from '../utils/prompt-generator.js';
|
|
31
31
|
import { loadTicketsFile, saveTicketsFile, updateTicketStatus, } from '../utils/tickets-manager.js';
|
|
32
|
+
import { migrateCore } from './migrate.js';
|
|
32
33
|
import { shipCore } from './ship.js';
|
|
34
|
+
import { testCore } from './test.js';
|
|
33
35
|
/**
|
|
34
36
|
* Prompt user for confirmation to continue
|
|
35
37
|
*/
|
|
@@ -52,38 +54,62 @@ async function promptConfirmation(message) {
|
|
|
52
54
|
function getTicketsToProcess(ticketsData) {
|
|
53
55
|
// Get all Todo and Error tickets (automatic retry on Error)
|
|
54
56
|
const tickets = ticketsData.tickets.filter((t) => t.status === 'Todo' || t.status === 'Error');
|
|
55
|
-
// Sort by phase: SCHEMA -> BACKEND -> FRONTEND
|
|
57
|
+
// Sort by phase: SCHEMA -> DB-TEST -> BACKEND -> FRONTEND -> WEB-TEST
|
|
56
58
|
tickets.sort((a, b) => {
|
|
57
59
|
const getPhaseOrder = (id) => {
|
|
58
60
|
if (id.startsWith('SCHEMA-'))
|
|
59
61
|
return 1;
|
|
60
|
-
if (id.startsWith('
|
|
62
|
+
if (id.startsWith('DB-TEST-'))
|
|
61
63
|
return 2;
|
|
62
|
-
if (id.startsWith('
|
|
64
|
+
if (id.startsWith('BACKEND-'))
|
|
63
65
|
return 3;
|
|
64
|
-
|
|
66
|
+
if (id.startsWith('FRONTEND-'))
|
|
67
|
+
return 4;
|
|
68
|
+
if (id.startsWith('WEB-TEST-'))
|
|
69
|
+
return 5;
|
|
70
|
+
return 6;
|
|
65
71
|
};
|
|
66
72
|
const phaseComparison = getPhaseOrder(a.id) - getPhaseOrder(b.id);
|
|
67
73
|
if (phaseComparison !== 0)
|
|
68
74
|
return phaseComparison;
|
|
69
75
|
// Within same phase, sort by ticket number
|
|
70
|
-
const aNum = parseInt(a.id.split('-')[
|
|
71
|
-
const bNum = parseInt(b.id.split('-')[
|
|
76
|
+
const aNum = parseInt(a.id.split('-').slice(-1)[0] || '0', 10);
|
|
77
|
+
const bNum = parseInt(b.id.split('-').slice(-1)[0] || '0', 10);
|
|
72
78
|
return aNum - bNum;
|
|
73
79
|
});
|
|
74
80
|
return tickets;
|
|
75
81
|
}
|
|
76
82
|
/**
|
|
77
|
-
* Commit
|
|
83
|
+
* Commit batch of tickets to current branch
|
|
78
84
|
*/
|
|
79
|
-
async function
|
|
85
|
+
async function commitBatch(batchTickets, cwd) {
|
|
80
86
|
const git = simpleGit(cwd);
|
|
81
87
|
// Stage all changes
|
|
82
88
|
await git.add('.');
|
|
83
|
-
//
|
|
84
|
-
const
|
|
89
|
+
// Create commit message with all tickets in batch
|
|
90
|
+
const ticketIds = batchTickets.map((t) => t.id).join(', ');
|
|
91
|
+
const batchType = batchTickets[0].id.startsWith('WEB-TEST-')
|
|
92
|
+
? batchTickets[0].id.split('-')[2] === '1'
|
|
93
|
+
? 'scaffold'
|
|
94
|
+
: 'logic'
|
|
95
|
+
: 'implementation';
|
|
96
|
+
const commitMessage = `feat: ${batchType} batch (${ticketIds})`;
|
|
85
97
|
await git.commit(commitMessage);
|
|
86
|
-
console.log(
|
|
98
|
+
console.log(`\n ā
Committed batch: ${commitMessage}\n`);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Determine if we should commit after this ticket
|
|
102
|
+
* Commits happen after the last WEB-TEST in a batch
|
|
103
|
+
*/
|
|
104
|
+
function shouldCommitAfterTicket(currentTicket, nextTicket) {
|
|
105
|
+
// Always commit after last ticket
|
|
106
|
+
if (!nextTicket)
|
|
107
|
+
return true;
|
|
108
|
+
// Commit if current is WEB-TEST and next is not WEB-TEST (batch boundary)
|
|
109
|
+
if (currentTicket.id.startsWith('WEB-TEST-') && !nextTicket.id.startsWith('WEB-TEST-')) {
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
return false;
|
|
87
113
|
}
|
|
88
114
|
/**
|
|
89
115
|
* Main build command - processes all tickets and commits each one
|
|
@@ -98,7 +124,7 @@ export async function buildCommand(options) {
|
|
|
98
124
|
if (!process.env.GITHUB_TOKEN) {
|
|
99
125
|
throw new Error('GITHUB_TOKEN environment variable is required for build command');
|
|
100
126
|
}
|
|
101
|
-
const { directory, ticketsFile = 'tickets.json', dbUrl = 'postgres://postgres:postgres@localhost:5432/postgres', reset = false, askConfirm = false, askCommit = false, review = true,
|
|
127
|
+
const { directory, ticketsFile = 'tickets.json', dbUrl = 'postgres://postgres:postgres@localhost:5432/postgres', reset = false, askConfirm = false, askCommit = false, review = true, url, headless, verbose, noLogs = false, } = options;
|
|
102
128
|
// 1. Validate and resolve directory
|
|
103
129
|
const cwd = directory ? resolve(directory) : process.cwd();
|
|
104
130
|
if (!existsSync(cwd)) {
|
|
@@ -141,9 +167,11 @@ export async function buildCommand(options) {
|
|
|
141
167
|
console.log(` ${index + 1}. ${ticket.id}: ${ticket.title}`);
|
|
142
168
|
});
|
|
143
169
|
console.log('');
|
|
144
|
-
// 4. Process each ticket sequentially
|
|
170
|
+
// 4. Process each ticket sequentially with batch tracking
|
|
171
|
+
const batchTickets = []; // Track tickets in current batch
|
|
145
172
|
for (let i = 0; i < ticketsToProcess.length; i++) {
|
|
146
173
|
const ticket = ticketsToProcess[i];
|
|
174
|
+
const nextTicket = ticketsToProcess[i + 1];
|
|
147
175
|
console.log('\n' + '='.repeat(80));
|
|
148
176
|
console.log(`š¦ Processing Ticket ${i + 1}/${ticketsToProcess.length}: ${ticket.id}`);
|
|
149
177
|
console.log(`š ${ticket.title}`);
|
|
@@ -153,59 +181,148 @@ export async function buildCommand(options) {
|
|
|
153
181
|
console.log('š Updating ticket status to InProgress...');
|
|
154
182
|
updateTicketStatus(ticketsPath, ticket.id, 'InProgress');
|
|
155
183
|
console.log(' ā
Status updated\n');
|
|
156
|
-
// Step 2:
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
directory: cwd,
|
|
161
|
-
dbUrl,
|
|
162
|
-
noLogs,
|
|
163
|
-
});
|
|
164
|
-
if (!shipResult.success) {
|
|
165
|
-
throw new Error(shipResult.error || 'Ship failed');
|
|
166
|
-
}
|
|
167
|
-
console.log(`\nā
${ticket.id} implemented successfully`);
|
|
168
|
-
console.log(`š Implementation fixes: ${shipResult.implementationFixCount}`);
|
|
169
|
-
console.log(`š§ Linting fixes: ${shipResult.lintFixCount}`);
|
|
170
|
-
if (shipResult.reviewFixCount > 0) {
|
|
171
|
-
console.log(`š Review fixes: ${shipResult.reviewFixCount}`);
|
|
172
|
-
}
|
|
173
|
-
console.log(`š° Ship cost: $${shipResult.cost.toFixed(4)}`);
|
|
174
|
-
// Step 3: Run tests if frontend ticket and test enabled
|
|
175
|
-
const isFrontendTicket = ticket.id.startsWith('FRONTEND-');
|
|
176
|
-
if (test && isFrontendTicket) {
|
|
184
|
+
// Step 2: Process ticket based on type
|
|
185
|
+
const isTestTicket = ticket.type === 'test';
|
|
186
|
+
if (isTestTicket) {
|
|
187
|
+
// This is a test ticket - run test with retry
|
|
177
188
|
console.log(`\n${'='.repeat(60)}`);
|
|
178
|
-
console.log(`š§Ŗ
|
|
189
|
+
console.log(`š§Ŗ Running Test`);
|
|
179
190
|
console.log(`${'='.repeat(60)}\n`);
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
191
|
+
// Generate test prompt from ticket
|
|
192
|
+
const testPrompt = generateWebTestPrompt(ticket);
|
|
193
|
+
let testResult = await testCore({
|
|
194
|
+
prompt: testPrompt,
|
|
195
|
+
context: {
|
|
196
|
+
ticketId: ticket.id,
|
|
197
|
+
ticketTitle: ticket.title,
|
|
198
|
+
ticketDescription: ticket.description,
|
|
199
|
+
},
|
|
183
200
|
url,
|
|
184
201
|
headless,
|
|
185
202
|
verbose,
|
|
186
|
-
|
|
203
|
+
noLogs,
|
|
187
204
|
});
|
|
188
|
-
|
|
189
|
-
|
|
205
|
+
let retryCount = 0;
|
|
206
|
+
const maxRetries = 3;
|
|
207
|
+
// Retry loop: if test fails, run ship to fix it
|
|
208
|
+
while (!testResult.success && retryCount < maxRetries) {
|
|
209
|
+
retryCount++;
|
|
210
|
+
console.log(`\nā ļø Test failed (attempt ${retryCount}/${maxRetries})`);
|
|
211
|
+
console.log(`š Error: ${testResult.error}\n`);
|
|
212
|
+
console.log(`š§ Running ship to fix test failures...\n`);
|
|
213
|
+
// Create a fix ticket for ship
|
|
214
|
+
const fixTicket = {
|
|
215
|
+
id: `${ticket.id}-FIX-${retryCount}`,
|
|
216
|
+
title: `Fix ${ticket.id} test failures`,
|
|
217
|
+
description: `Fix the following test failures:\n\n${testResult.error}\n\nOriginal ticket:\n${ticket.description}`,
|
|
218
|
+
type: 'backend', // Use backend type for test fix tickets
|
|
219
|
+
estimatedEffort: 5,
|
|
220
|
+
status: 'InProgress',
|
|
221
|
+
category: ticket.category,
|
|
222
|
+
};
|
|
223
|
+
const shipResult = await shipCore({
|
|
224
|
+
ticketData: fixTicket,
|
|
225
|
+
review: false, // Skip review for test fixes
|
|
226
|
+
directory: cwd,
|
|
227
|
+
dbUrl,
|
|
228
|
+
noLogs,
|
|
229
|
+
});
|
|
230
|
+
if (!shipResult.success) {
|
|
231
|
+
console.error(`\nā Fix attempt ${retryCount} failed: ${shipResult.error}`);
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
console.log(`\nā
Fix applied (attempt ${retryCount})`);
|
|
235
|
+
console.log(`š° Fix cost: $${shipResult.cost.toFixed(4)}\n`);
|
|
236
|
+
// Re-run test
|
|
237
|
+
console.log(`š Re-running test...\n`);
|
|
238
|
+
testResult = await testCore({
|
|
239
|
+
prompt: testPrompt,
|
|
240
|
+
context: {
|
|
241
|
+
ticketId: ticket.id,
|
|
242
|
+
ticketTitle: ticket.title,
|
|
243
|
+
ticketDescription: ticket.description,
|
|
244
|
+
},
|
|
245
|
+
url,
|
|
246
|
+
headless,
|
|
247
|
+
verbose,
|
|
248
|
+
noLogs,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
if (!testResult.success) {
|
|
252
|
+
throw new Error(`Test failed after ${maxRetries} fix attempts:\n${testResult.error}`);
|
|
253
|
+
}
|
|
254
|
+
console.log(`\nā
${ticket.id} test passed`);
|
|
255
|
+
console.log(`š° Test cost: $${testResult.cost.toFixed(4)}`);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
// Regular implementation ticket - run ship
|
|
259
|
+
const shipResult = await shipCore({
|
|
260
|
+
ticketData: ticket,
|
|
261
|
+
review,
|
|
262
|
+
directory: cwd,
|
|
263
|
+
dbUrl,
|
|
264
|
+
noLogs,
|
|
265
|
+
});
|
|
266
|
+
if (!shipResult.success) {
|
|
267
|
+
throw new Error(shipResult.error || 'Ship failed');
|
|
268
|
+
}
|
|
269
|
+
console.log(`\nā
${ticket.id} implemented successfully`);
|
|
270
|
+
console.log(`š Implementation fixes: ${shipResult.implementationFixCount}`);
|
|
271
|
+
console.log(`š§ Linting fixes: ${shipResult.lintFixCount}`);
|
|
272
|
+
if (shipResult.reviewFixCount > 0) {
|
|
273
|
+
console.log(`š Review fixes: ${shipResult.reviewFixCount}`);
|
|
274
|
+
}
|
|
275
|
+
console.log(`š° Ship cost: $${shipResult.cost.toFixed(4)}`);
|
|
276
|
+
// If this is a schema ticket, run migrations
|
|
277
|
+
if (ticket.type === 'schema') {
|
|
278
|
+
console.log(`\n${'='.repeat(60)}`);
|
|
279
|
+
console.log(`šļø Phase 4: Database Migration & Validation`);
|
|
280
|
+
console.log(`${'='.repeat(60)}\n`);
|
|
281
|
+
const migrateResult = await migrateCore({
|
|
282
|
+
directory: cwd,
|
|
283
|
+
dbUrl,
|
|
284
|
+
context: {
|
|
285
|
+
ticketId: ticket.id,
|
|
286
|
+
ticketTitle: ticket.title,
|
|
287
|
+
ticketDescription: ticket.description,
|
|
288
|
+
},
|
|
289
|
+
noLogs,
|
|
290
|
+
});
|
|
291
|
+
if (!migrateResult.success) {
|
|
292
|
+
throw new Error(`Migration failed: ${migrateResult.error}`);
|
|
293
|
+
}
|
|
294
|
+
console.log(`\nā
Migrations applied and validated`);
|
|
295
|
+
console.log(` ā Migrations applied: ${migrateResult.migrationsApplied}`);
|
|
296
|
+
console.log(` ā Seeding completed: ${migrateResult.seedingCompleted}`);
|
|
297
|
+
console.log(` ā Validation passed: ${migrateResult.validationPassed}`);
|
|
298
|
+
console.log(`š° Migration cost: $${migrateResult.cost.toFixed(4)}`);
|
|
299
|
+
}
|
|
190
300
|
}
|
|
191
|
-
// Step
|
|
301
|
+
// Step 3: Update ticket status to Done
|
|
192
302
|
console.log('\nš Updating ticket status to Done...');
|
|
193
303
|
updateTicketStatus(ticketsPath, ticket.id, 'Done');
|
|
194
304
|
console.log(` ā
Ticket ${ticket.id} marked as Done\n`);
|
|
195
|
-
//
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
305
|
+
// Add to batch tracking
|
|
306
|
+
batchTickets.push(ticket);
|
|
307
|
+
// Step 4: Commit batch if at batch boundary
|
|
308
|
+
const shouldCommit = shouldCommitAfterTicket(ticket, nextTicket);
|
|
309
|
+
if (shouldCommit && batchTickets.length > 0) {
|
|
310
|
+
if (askCommit) {
|
|
311
|
+
// Interactive: ask before committing
|
|
312
|
+
const commitConfirmed = await promptConfirmation(`\nā Commit batch of ${batchTickets.length} ticket(s)?`);
|
|
313
|
+
if (commitConfirmed) {
|
|
314
|
+
await commitBatch(batchTickets, cwd);
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
console.log(' āļø Skipped batch commit\n');
|
|
318
|
+
}
|
|
201
319
|
}
|
|
202
320
|
else {
|
|
203
|
-
|
|
321
|
+
// Default: auto-commit batch
|
|
322
|
+
await commitBatch(batchTickets, cwd);
|
|
204
323
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
// Default: auto-commit
|
|
208
|
-
await commitTicket(ticket, cwd);
|
|
324
|
+
// Reset batch tracking
|
|
325
|
+
batchTickets.length = 0;
|
|
209
326
|
}
|
|
210
327
|
// Ask for confirmation before proceeding to next ticket (if not last ticket)
|
|
211
328
|
if (askConfirm && i < ticketsToProcess.length - 1) {
|