@kosuke-ai/cli 0.0.56 → 1.0.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.
- package/README.md +31 -448
- package/dist/commands/auth.js +117 -0
- package/dist/generated/commands/deploy/cancel.js +17 -0
- package/dist/generated/commands/deploy/messages.js +17 -0
- package/dist/generated/commands/deploy/run.js +60 -0
- package/dist/generated/commands/index.js +132 -0
- package/dist/generated/commands/preview/get.js +25 -0
- package/dist/generated/commands/preview/health.js +25 -0
- package/dist/generated/commands/preview/reset.js +27 -0
- package/dist/generated/commands/preview/share-create.js +36 -0
- package/dist/generated/commands/preview/share-delete.js +26 -0
- package/dist/generated/commands/preview/share-get.js +26 -0
- package/dist/generated/commands/preview/shared.js +17 -0
- package/dist/generated/commands/projects/create.js +37 -0
- package/dist/generated/commands/projects/delete.js +17 -0
- package/dist/generated/commands/projects/env-vars-add.js +21 -0
- package/dist/generated/commands/projects/env-vars-remove.js +21 -0
- package/dist/generated/commands/projects/get.js +17 -0
- package/dist/generated/commands/projects/list.js +15 -0
- package/dist/generated/commands/projects/services-add.js +87 -0
- package/dist/generated/commands/projects/services-list.js +18 -0
- package/dist/generated/commands/projects/services-remove.js +19 -0
- package/dist/generated/commands/projects/services-update.js +81 -0
- package/dist/generated/commands/projects/settings-get.js +18 -0
- package/dist/generated/commands/projects/settings-import.js +91 -0
- package/dist/generated/commands/projects/settings-update.js +77 -0
- package/dist/generated/commands/projects/skills.js +35 -0
- package/dist/generated/commands/projects/update.js +27 -0
- package/dist/generated/commands/sessions/activate.js +18 -0
- package/dist/generated/commands/sessions/checklist-generate.js +19 -0
- package/dist/generated/commands/sessions/checklist-get.js +19 -0
- package/dist/generated/commands/sessions/comments-add.js +63 -0
- package/dist/generated/commands/sessions/comments-delete.js +20 -0
- package/dist/generated/commands/sessions/comments-list.js +19 -0
- package/dist/generated/commands/sessions/comments-update.js +23 -0
- package/dist/generated/commands/sessions/create.js +126 -0
- package/dist/generated/commands/sessions/delete.js +18 -0
- package/dist/generated/commands/sessions/diff-files.js +19 -0
- package/dist/generated/commands/sessions/diff-patch.js +86 -0
- package/dist/generated/commands/sessions/edit-prompt.js +59 -0
- package/dist/generated/commands/sessions/files-get.js +27 -0
- package/dist/generated/commands/sessions/files-list.js +19 -0
- package/dist/generated/commands/sessions/files-write.js +41 -0
- package/dist/generated/commands/sessions/get.js +18 -0
- package/dist/generated/commands/sessions/git-commit-message.js +19 -0
- package/dist/generated/commands/sessions/git-commit.js +29 -0
- package/dist/generated/commands/sessions/git-push.js +19 -0
- package/dist/generated/commands/sessions/git-state.js +19 -0
- package/dist/generated/commands/sessions/jobs-cancel.js +20 -0
- package/dist/generated/commands/sessions/jobs-get.js +20 -0
- package/dist/generated/commands/sessions/list.js +81 -0
- package/dist/generated/commands/sessions/messages.js +18 -0
- package/dist/generated/commands/sessions/search.js +23 -0
- package/dist/generated/commands/sessions/send.js +98 -0
- package/dist/generated/commands/sessions/update.js +72 -0
- package/dist/generated/commands/workspaces/access-status.js +29 -0
- package/dist/generated/commands/workspaces/ai-provider-get.js +18 -0
- package/dist/generated/commands/workspaces/ai-provider-remove.js +42 -0
- package/dist/generated/commands/workspaces/ai-provider-set.js +21 -0
- package/dist/generated/commands/workspaces/credits.js +17 -0
- package/dist/generated/commands/workspaces/get.js +17 -0
- package/dist/generated/commands/workspaces/getting-started-get.js +18 -0
- package/dist/generated/commands/workspaces/getting-started-update.js +32 -0
- package/dist/generated/commands/workspaces/list.js +15 -0
- package/dist/generated/commands/workspaces/members.js +25 -0
- package/dist/generated/commands/workspaces/sandbox-limit.js +17 -0
- package/dist/generated/commands/workspaces/stop-sandboxes.js +27 -0
- package/dist/generated/commands/workspaces/usage.js +32 -0
- package/dist/index.js +5 -516
- package/dist/program.js +46 -0
- package/dist/runtime/attach.js +139 -0
- package/dist/runtime/attachments.js +58 -0
- package/dist/runtime/client.js +12 -0
- package/dist/runtime/config.js +49 -0
- package/dist/runtime/credentials.js +24 -0
- package/dist/runtime/descriptor.js +7 -0
- package/dist/runtime/invoke.js +152 -0
- package/dist/runtime/runtime.js +41 -0
- package/dist/runtime/version.js +5 -0
- package/openapi.json +5222 -0
- package/package.json +21 -79
- package/LICENSE +0 -21
- package/claude.costs.json +0 -34
- package/dist/__tests__/utils/file-discovery.test.d.ts +0 -5
- package/dist/__tests__/utils/file-discovery.test.d.ts.map +0 -1
- package/dist/__tests__/utils/file-discovery.test.js +0 -51
- package/dist/__tests__/utils/file-discovery.test.js.map +0 -1
- package/dist/__tests__/utils/logger-nologs.test.d.ts +0 -5
- package/dist/__tests__/utils/logger-nologs.test.d.ts.map +0 -1
- package/dist/__tests__/utils/logger-nologs.test.js +0 -34
- package/dist/__tests__/utils/logger-nologs.test.js.map +0 -1
- package/dist/__tests__/utils/logger.test.d.ts +0 -5
- package/dist/__tests__/utils/logger.test.d.ts.map +0 -1
- package/dist/__tests__/utils/logger.test.js +0 -243
- package/dist/__tests__/utils/logger.test.js.map +0 -1
- package/dist/__tests__/utils/validator.test.d.ts +0 -5
- package/dist/__tests__/utils/validator.test.d.ts.map +0 -1
- package/dist/__tests__/utils/validator.test.js +0 -206
- package/dist/__tests__/utils/validator.test.js.map +0 -1
- package/dist/index.d.ts +0 -35
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/kosuke/commands/analyse.d.ts +0 -15
- package/dist/kosuke/commands/analyse.d.ts.map +0 -1
- package/dist/kosuke/commands/analyse.js +0 -273
- package/dist/kosuke/commands/analyse.js.map +0 -1
- package/dist/kosuke/commands/build.d.ts +0 -35
- package/dist/kosuke/commands/build.d.ts.map +0 -1
- package/dist/kosuke/commands/build.js +0 -659
- package/dist/kosuke/commands/build.js.map +0 -1
- package/dist/kosuke/commands/getcode.d.ts +0 -29
- package/dist/kosuke/commands/getcode.d.ts.map +0 -1
- package/dist/kosuke/commands/getcode.js +0 -221
- package/dist/kosuke/commands/getcode.js.map +0 -1
- package/dist/kosuke/commands/lint.d.ts +0 -21
- package/dist/kosuke/commands/lint.d.ts.map +0 -1
- package/dist/kosuke/commands/lint.js +0 -321
- package/dist/kosuke/commands/lint.js.map +0 -1
- package/dist/kosuke/commands/migrate.d.ts +0 -38
- package/dist/kosuke/commands/migrate.d.ts.map +0 -1
- package/dist/kosuke/commands/migrate.js +0 -284
- package/dist/kosuke/commands/migrate.js.map +0 -1
- package/dist/kosuke/commands/plan.d.ts +0 -28
- package/dist/kosuke/commands/plan.d.ts.map +0 -1
- package/dist/kosuke/commands/plan.js +0 -630
- package/dist/kosuke/commands/plan.js.map +0 -1
- package/dist/kosuke/commands/requirements.d.ts +0 -52
- package/dist/kosuke/commands/requirements.d.ts.map +0 -1
- package/dist/kosuke/commands/requirements.js +0 -615
- package/dist/kosuke/commands/requirements.js.map +0 -1
- package/dist/kosuke/commands/review.d.ts +0 -26
- package/dist/kosuke/commands/review.d.ts.map +0 -1
- package/dist/kosuke/commands/review.js +0 -303
- package/dist/kosuke/commands/review.js.map +0 -1
- package/dist/kosuke/commands/serve.d.ts +0 -9
- package/dist/kosuke/commands/serve.d.ts.map +0 -1
- package/dist/kosuke/commands/serve.js +0 -17
- package/dist/kosuke/commands/serve.js.map +0 -1
- package/dist/kosuke/commands/ship.d.ts +0 -37
- package/dist/kosuke/commands/ship.d.ts.map +0 -1
- package/dist/kosuke/commands/ship.js +0 -375
- package/dist/kosuke/commands/ship.js.map +0 -1
- package/dist/kosuke/commands/sync-rules.d.ts +0 -9
- package/dist/kosuke/commands/sync-rules.d.ts.map +0 -1
- package/dist/kosuke/commands/sync-rules.js +0 -379
- package/dist/kosuke/commands/sync-rules.js.map +0 -1
- package/dist/kosuke/commands/test.d.ts +0 -42
- package/dist/kosuke/commands/test.d.ts.map +0 -1
- package/dist/kosuke/commands/test.js +0 -540
- package/dist/kosuke/commands/test.js.map +0 -1
- package/dist/kosuke/commands/tickets.d.ts +0 -43
- package/dist/kosuke/commands/tickets.d.ts.map +0 -1
- package/dist/kosuke/commands/tickets.js +0 -499
- package/dist/kosuke/commands/tickets.js.map +0 -1
- package/dist/kosuke/serve/middleware/error-handler.d.ts +0 -14
- package/dist/kosuke/serve/middleware/error-handler.d.ts.map +0 -1
- package/dist/kosuke/serve/middleware/error-handler.js +0 -42
- package/dist/kosuke/serve/middleware/error-handler.js.map +0 -1
- package/dist/kosuke/serve/middleware/validation.d.ts +0 -13
- package/dist/kosuke/serve/middleware/validation.d.ts.map +0 -1
- package/dist/kosuke/serve/middleware/validation.js +0 -38
- package/dist/kosuke/serve/middleware/validation.js.map +0 -1
- package/dist/kosuke/serve/routes/build.d.ts +0 -6
- package/dist/kosuke/serve/routes/build.d.ts.map +0 -1
- package/dist/kosuke/serve/routes/build.js +0 -226
- package/dist/kosuke/serve/routes/build.js.map +0 -1
- package/dist/kosuke/serve/routes/health.d.ts +0 -6
- package/dist/kosuke/serve/routes/health.d.ts.map +0 -1
- package/dist/kosuke/serve/routes/health.js +0 -11
- package/dist/kosuke/serve/routes/health.js.map +0 -1
- package/dist/kosuke/serve/routes/plan.d.ts +0 -6
- package/dist/kosuke/serve/routes/plan.d.ts.map +0 -1
- package/dist/kosuke/serve/routes/plan.js +0 -106
- package/dist/kosuke/serve/routes/plan.js.map +0 -1
- package/dist/kosuke/serve/server.d.ts +0 -16
- package/dist/kosuke/serve/server.d.ts.map +0 -1
- package/dist/kosuke/serve/server.js +0 -67
- package/dist/kosuke/serve/server.js.map +0 -1
- package/dist/kosuke/serve/validation/build.d.ts +0 -41
- package/dist/kosuke/serve/validation/build.d.ts.map +0 -1
- package/dist/kosuke/serve/validation/build.js +0 -20
- package/dist/kosuke/serve/validation/build.js.map +0 -1
- package/dist/kosuke/serve/validation/plan.d.ts +0 -26
- package/dist/kosuke/serve/validation/plan.d.ts.map +0 -1
- package/dist/kosuke/serve/validation/plan.js +0 -15
- package/dist/kosuke/serve/validation/plan.js.map +0 -1
- package/dist/kosuke/types.d.ts +0 -469
- package/dist/kosuke/types.d.ts.map +0 -1
- package/dist/kosuke/types.js +0 -5
- package/dist/kosuke/types.js.map +0 -1
- package/dist/kosuke/utils/batch-creator.d.ts +0 -14
- package/dist/kosuke/utils/batch-creator.d.ts.map +0 -1
- package/dist/kosuke/utils/batch-creator.js +0 -76
- package/dist/kosuke/utils/batch-creator.js.map +0 -1
- package/dist/kosuke/utils/claude-agent.d.ts +0 -145
- package/dist/kosuke/utils/claude-agent.d.ts.map +0 -1
- package/dist/kosuke/utils/claude-agent.js +0 -504
- package/dist/kosuke/utils/claude-agent.js.map +0 -1
- package/dist/kosuke/utils/constants.d.ts +0 -40
- package/dist/kosuke/utils/constants.d.ts.map +0 -1
- package/dist/kosuke/utils/constants.js +0 -54
- package/dist/kosuke/utils/constants.js.map +0 -1
- package/dist/kosuke/utils/file-discovery.d.ts +0 -15
- package/dist/kosuke/utils/file-discovery.d.ts.map +0 -1
- package/dist/kosuke/utils/file-discovery.js +0 -80
- package/dist/kosuke/utils/file-discovery.js.map +0 -1
- package/dist/kosuke/utils/git.d.ts +0 -41
- package/dist/kosuke/utils/git.d.ts.map +0 -1
- package/dist/kosuke/utils/git.js +0 -145
- package/dist/kosuke/utils/git.js.map +0 -1
- package/dist/kosuke/utils/github.d.ts +0 -17
- package/dist/kosuke/utils/github.d.ts.map +0 -1
- package/dist/kosuke/utils/github.js +0 -22
- package/dist/kosuke/utils/github.js.map +0 -1
- package/dist/kosuke/utils/interactive-input.d.ts +0 -22
- package/dist/kosuke/utils/interactive-input.d.ts.map +0 -1
- package/dist/kosuke/utils/interactive-input.js +0 -124
- package/dist/kosuke/utils/interactive-input.js.map +0 -1
- package/dist/kosuke/utils/logger.d.ts +0 -161
- package/dist/kosuke/utils/logger.d.ts.map +0 -1
- package/dist/kosuke/utils/logger.js +0 -234
- package/dist/kosuke/utils/logger.js.map +0 -1
- package/dist/kosuke/utils/playwright-mcp-client.d.ts +0 -46
- package/dist/kosuke/utils/playwright-mcp-client.d.ts.map +0 -1
- package/dist/kosuke/utils/playwright-mcp-client.js +0 -135
- package/dist/kosuke/utils/playwright-mcp-client.js.map +0 -1
- package/dist/kosuke/utils/pr-orchestrator.d.ts +0 -49
- package/dist/kosuke/utils/pr-orchestrator.d.ts.map +0 -1
- package/dist/kosuke/utils/pr-orchestrator.js +0 -154
- package/dist/kosuke/utils/pr-orchestrator.js.map +0 -1
- package/dist/kosuke/utils/repository-manager.d.ts +0 -13
- package/dist/kosuke/utils/repository-manager.d.ts.map +0 -1
- package/dist/kosuke/utils/repository-manager.js +0 -94
- package/dist/kosuke/utils/repository-manager.js.map +0 -1
- package/dist/kosuke/utils/repository-resolver.d.ts +0 -12
- package/dist/kosuke/utils/repository-resolver.d.ts.map +0 -1
- package/dist/kosuke/utils/repository-resolver.js +0 -186
- package/dist/kosuke/utils/repository-resolver.js.map +0 -1
- package/dist/kosuke/utils/tickets-manager.d.ts +0 -64
- package/dist/kosuke/utils/tickets-manager.d.ts.map +0 -1
- package/dist/kosuke/utils/tickets-manager.js +0 -331
- package/dist/kosuke/utils/tickets-manager.js.map +0 -1
- package/dist/kosuke/utils/validator.d.ts +0 -45
- package/dist/kosuke/utils/validator.d.ts.map +0 -1
- package/dist/kosuke/utils/validator.js +0 -248
- package/dist/kosuke/utils/validator.js.map +0 -1
- package/dist/lib.d.ts +0 -96
- package/dist/lib.d.ts.map +0 -1
- package/dist/lib.js +0 -95
- package/dist/lib.js.map +0 -1
- package/dist/package.json +0 -99
|
@@ -1,659 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Build command - Process all tickets from tickets.json
|
|
3
|
-
*
|
|
4
|
-
* This command processes all "Todo" and "Error" tickets sequentially,
|
|
5
|
-
* implementing each one using the ship core engine and committing after each ticket.
|
|
6
|
-
* Frontend tickets automatically run tests (unless --no-test is specified).
|
|
7
|
-
* All tickets include code review by default (unless --no-review is specified).
|
|
8
|
-
*
|
|
9
|
-
* Usage:
|
|
10
|
-
* kosuke build # Process and auto-commit all tickets
|
|
11
|
-
* kosuke build --ask-commit # Ask before committing each ticket
|
|
12
|
-
* kosuke build --ask-confirm # Ask before processing each ticket
|
|
13
|
-
* kosuke build --reset # Reset all tickets to "Todo" and process from scratch
|
|
14
|
-
* kosuke build --no-review # Skip code review phase
|
|
15
|
-
* kosuke build --no-test # Skip testing phase for frontend tickets
|
|
16
|
-
* kosuke build --headless # Run tests in headless mode (invisible)
|
|
17
|
-
* kosuke build --verbose # Enable verbose test output
|
|
18
|
-
* kosuke build --tickets=path/to/tickets.json
|
|
19
|
-
* kosuke build --db-url=postgres://user:pass@host:5432/db
|
|
20
|
-
*
|
|
21
|
-
* Note: Create a feature branch before running build:
|
|
22
|
-
* git checkout -b feat/implement-tickets
|
|
23
|
-
* kosuke build
|
|
24
|
-
* gh pr create
|
|
25
|
-
*/
|
|
26
|
-
import { existsSync, statSync } from 'fs';
|
|
27
|
-
import { join, resolve } from 'path';
|
|
28
|
-
import * as readline from 'readline';
|
|
29
|
-
import simpleGit from 'simple-git';
|
|
30
|
-
import { DEFAULT_DB_URL } from '../utils/constants.js';
|
|
31
|
-
import { loadTicketsFile, saveTicketsFile, updateTicketStatus, } from '../utils/tickets-manager.js';
|
|
32
|
-
import { migrateCoreStream } from './migrate.js';
|
|
33
|
-
import { migrateCore } from './migrate.js';
|
|
34
|
-
import { shipCoreStream } from './ship.js';
|
|
35
|
-
import { shipCore } from './ship.js';
|
|
36
|
-
import { testCoreStream } from './test.js';
|
|
37
|
-
import { testCore } from './test.js';
|
|
38
|
-
/**
|
|
39
|
-
* Generate a structured web test prompt from a ticket
|
|
40
|
-
*/
|
|
41
|
-
function generateWebTestPrompt(ticket) {
|
|
42
|
-
return `Test the following feature implementation:
|
|
43
|
-
|
|
44
|
-
**Feature:** ${ticket.title}
|
|
45
|
-
|
|
46
|
-
**Requirements:**
|
|
47
|
-
${ticket.description}
|
|
48
|
-
|
|
49
|
-
**Testing Instructions:**
|
|
50
|
-
1. Navigate to the relevant page(s) for this feature
|
|
51
|
-
2. Verify all functionality described in the requirements works correctly
|
|
52
|
-
3. Check for any console errors or warnings
|
|
53
|
-
4. Confirm the implementation matches the ticket description
|
|
54
|
-
5. Test both happy path and edge cases
|
|
55
|
-
|
|
56
|
-
**Success Criteria:**
|
|
57
|
-
- All functionality works as described
|
|
58
|
-
- No console errors
|
|
59
|
-
- User experience is smooth and intuitive
|
|
60
|
-
- Feature behaves correctly in different scenarios
|
|
61
|
-
|
|
62
|
-
Return a clear success or failure status with details about what was tested and any issues found.`;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Prompt user for confirmation to continue
|
|
66
|
-
*/
|
|
67
|
-
async function promptConfirmation(message) {
|
|
68
|
-
const rl = readline.createInterface({
|
|
69
|
-
input: process.stdin,
|
|
70
|
-
output: process.stdout,
|
|
71
|
-
});
|
|
72
|
-
return new Promise((resolve) => {
|
|
73
|
-
rl.question(`\n${message} (y/n): `, (answer) => {
|
|
74
|
-
rl.close();
|
|
75
|
-
const response = answer.trim().toLowerCase();
|
|
76
|
-
resolve(response === 'y' || response === 'yes');
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Filter and sort tickets for processing
|
|
82
|
-
*/
|
|
83
|
-
function getTicketsToProcess(ticketsData) {
|
|
84
|
-
// Get all Todo and Error tickets (automatic retry on Error)
|
|
85
|
-
const tickets = ticketsData.tickets.filter((t) => t.status === 'Todo' || t.status === 'Error');
|
|
86
|
-
// Sort by phase: SCHEMA -> DB-TEST -> BACKEND -> FRONTEND -> WEB-TEST
|
|
87
|
-
tickets.sort((a, b) => {
|
|
88
|
-
const getPhaseOrder = (id) => {
|
|
89
|
-
if (id.startsWith('SCHEMA-'))
|
|
90
|
-
return 1;
|
|
91
|
-
if (id.startsWith('DB-TEST-'))
|
|
92
|
-
return 2;
|
|
93
|
-
if (id.startsWith('BACKEND-'))
|
|
94
|
-
return 3;
|
|
95
|
-
if (id.startsWith('FRONTEND-'))
|
|
96
|
-
return 4;
|
|
97
|
-
if (id.startsWith('WEB-TEST-'))
|
|
98
|
-
return 5;
|
|
99
|
-
return 6;
|
|
100
|
-
};
|
|
101
|
-
const phaseComparison = getPhaseOrder(a.id) - getPhaseOrder(b.id);
|
|
102
|
-
if (phaseComparison !== 0)
|
|
103
|
-
return phaseComparison;
|
|
104
|
-
// Within same phase, sort by ticket number
|
|
105
|
-
const aNum = parseInt(a.id.split('-').slice(-1)[0] || '0', 10);
|
|
106
|
-
const bNum = parseInt(b.id.split('-').slice(-1)[0] || '0', 10);
|
|
107
|
-
return aNum - bNum;
|
|
108
|
-
});
|
|
109
|
-
return tickets;
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Commit a single ticket to current branch
|
|
113
|
-
* Returns the commit message
|
|
114
|
-
*/
|
|
115
|
-
async function commitTicket(ticket, cwd) {
|
|
116
|
-
const git = simpleGit(cwd);
|
|
117
|
-
// Stage all changes
|
|
118
|
-
await git.add('.');
|
|
119
|
-
// Create commit message for this ticket
|
|
120
|
-
const ticketType = ticket.type || 'feat';
|
|
121
|
-
const commitMessage = `${ticketType}: ${ticket.id} - ${ticket.title}`;
|
|
122
|
-
await git.commit(commitMessage, ['--no-verify']);
|
|
123
|
-
return commitMessage;
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Streaming version of build - orchestrates all sub-commands with SSE events
|
|
127
|
-
*/
|
|
128
|
-
export async function* buildCoreStream(options) {
|
|
129
|
-
const { directory, ticketsFile = 'tickets.json', dbUrl = DEFAULT_DB_URL, reset = false, review = true, url, headless, verbose, trace, } = options;
|
|
130
|
-
// 1. Validate and resolve directory
|
|
131
|
-
const cwd = directory ? resolve(directory) : process.cwd();
|
|
132
|
-
if (!existsSync(cwd)) {
|
|
133
|
-
yield {
|
|
134
|
-
type: 'done',
|
|
135
|
-
data: {
|
|
136
|
-
success: false,
|
|
137
|
-
ticketsProcessed: 0,
|
|
138
|
-
ticketsSucceeded: 0,
|
|
139
|
-
ticketsFailed: 0,
|
|
140
|
-
totalCost: 0,
|
|
141
|
-
tokensUsed: { input: 0, output: 0, cacheCreation: 0, cacheRead: 0 },
|
|
142
|
-
},
|
|
143
|
-
};
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
const stats = statSync(cwd);
|
|
147
|
-
if (!stats.isDirectory()) {
|
|
148
|
-
yield {
|
|
149
|
-
type: 'done',
|
|
150
|
-
data: {
|
|
151
|
-
success: false,
|
|
152
|
-
ticketsProcessed: 0,
|
|
153
|
-
ticketsSucceeded: 0,
|
|
154
|
-
ticketsFailed: 0,
|
|
155
|
-
totalCost: 0,
|
|
156
|
-
tokensUsed: { input: 0, output: 0, cacheCreation: 0, cacheRead: 0 },
|
|
157
|
-
},
|
|
158
|
-
};
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
const ticketsPath = join(cwd, ticketsFile);
|
|
162
|
-
// 2. Load tickets
|
|
163
|
-
const ticketsData = loadTicketsFile(ticketsPath);
|
|
164
|
-
// 3. Reset all tickets to "Todo" if --reset flag is provided
|
|
165
|
-
if (reset) {
|
|
166
|
-
ticketsData.tickets.forEach((ticket) => {
|
|
167
|
-
if (ticket.status !== 'Todo') {
|
|
168
|
-
ticket.status = 'Todo';
|
|
169
|
-
delete ticket.error;
|
|
170
|
-
}
|
|
171
|
-
});
|
|
172
|
-
saveTicketsFile(ticketsPath, ticketsData);
|
|
173
|
-
}
|
|
174
|
-
const ticketsToProcess = getTicketsToProcess(ticketsData);
|
|
175
|
-
if (ticketsToProcess.length === 0) {
|
|
176
|
-
yield {
|
|
177
|
-
type: 'done',
|
|
178
|
-
data: {
|
|
179
|
-
success: true,
|
|
180
|
-
ticketsProcessed: 0,
|
|
181
|
-
ticketsSucceeded: 0,
|
|
182
|
-
ticketsFailed: 0,
|
|
183
|
-
totalCost: 0,
|
|
184
|
-
tokensUsed: { input: 0, output: 0, cacheCreation: 0, cacheRead: 0 },
|
|
185
|
-
},
|
|
186
|
-
};
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
// Yield build started event
|
|
190
|
-
yield {
|
|
191
|
-
type: 'build_started',
|
|
192
|
-
data: { totalTickets: ticketsToProcess.length, ticketsFile: ticketsPath },
|
|
193
|
-
};
|
|
194
|
-
// Track cumulative metrics
|
|
195
|
-
let totalInputTokens = 0;
|
|
196
|
-
let totalOutputTokens = 0;
|
|
197
|
-
let totalCacheCreationTokens = 0;
|
|
198
|
-
let totalCacheReadTokens = 0;
|
|
199
|
-
let totalCost = 0;
|
|
200
|
-
let ticketsSucceeded = 0;
|
|
201
|
-
let ticketsFailed = 0;
|
|
202
|
-
// 4. Process each ticket sequentially
|
|
203
|
-
for (let i = 0; i < ticketsToProcess.length; i++) {
|
|
204
|
-
const ticket = ticketsToProcess[i];
|
|
205
|
-
// Yield ticket started
|
|
206
|
-
yield {
|
|
207
|
-
type: 'ticket_started',
|
|
208
|
-
data: { ticket, index: i + 1, total: ticketsToProcess.length },
|
|
209
|
-
};
|
|
210
|
-
try {
|
|
211
|
-
// Update status to InProgress
|
|
212
|
-
updateTicketStatus(ticketsPath, ticket.id, 'InProgress');
|
|
213
|
-
// Process ticket based on type
|
|
214
|
-
const isTestTicket = ticket.type === 'test';
|
|
215
|
-
if (isTestTicket) {
|
|
216
|
-
// Test ticket with retry logic (Task 6)
|
|
217
|
-
yield { type: 'ticket_phase', data: { phase: 'test', status: 'started' } };
|
|
218
|
-
const testPrompt = generateWebTestPrompt(ticket);
|
|
219
|
-
let testSuccess = false;
|
|
220
|
-
let retryCount = 0;
|
|
221
|
-
const maxRetries = 3;
|
|
222
|
-
while (!testSuccess && retryCount <= maxRetries) {
|
|
223
|
-
// Run test
|
|
224
|
-
for await (const event of testCoreStream({
|
|
225
|
-
prompt: testPrompt,
|
|
226
|
-
context: {
|
|
227
|
-
ticketId: ticket.id,
|
|
228
|
-
ticketTitle: ticket.title,
|
|
229
|
-
ticketDescription: ticket.description,
|
|
230
|
-
},
|
|
231
|
-
url,
|
|
232
|
-
headless,
|
|
233
|
-
verbose,
|
|
234
|
-
trace,
|
|
235
|
-
})) {
|
|
236
|
-
yield { type: 'test_event', data: event };
|
|
237
|
-
if (event.type === 'done') {
|
|
238
|
-
const testResult = event.data;
|
|
239
|
-
testSuccess = testResult.success;
|
|
240
|
-
// Track metrics
|
|
241
|
-
totalInputTokens += testResult.tokensUsed.input;
|
|
242
|
-
totalOutputTokens += testResult.tokensUsed.output;
|
|
243
|
-
totalCacheCreationTokens += testResult.tokensUsed.cacheCreation;
|
|
244
|
-
totalCacheReadTokens += testResult.tokensUsed.cacheRead;
|
|
245
|
-
totalCost += testResult.cost;
|
|
246
|
-
// If test failed and we have retries left, create fix ticket
|
|
247
|
-
if (!testSuccess && retryCount < maxRetries) {
|
|
248
|
-
retryCount++;
|
|
249
|
-
yield {
|
|
250
|
-
type: 'test_retry',
|
|
251
|
-
data: {
|
|
252
|
-
attempt: retryCount,
|
|
253
|
-
maxRetries,
|
|
254
|
-
error: testResult.error || 'Test failed',
|
|
255
|
-
},
|
|
256
|
-
};
|
|
257
|
-
// Create fix ticket
|
|
258
|
-
const fixTicket = {
|
|
259
|
-
id: `${ticket.id}-FIX-${retryCount}`,
|
|
260
|
-
title: `Fix ${ticket.id} test failures`,
|
|
261
|
-
description: `Fix the following test failures:\n\n${testResult.error}\n\nOriginal ticket:\n${ticket.description}`,
|
|
262
|
-
type: 'backend',
|
|
263
|
-
estimatedEffort: 5,
|
|
264
|
-
status: 'InProgress',
|
|
265
|
-
category: ticket.category,
|
|
266
|
-
};
|
|
267
|
-
// Run ship to fix test
|
|
268
|
-
for await (const shipEvent of shipCoreStream({
|
|
269
|
-
ticketData: fixTicket,
|
|
270
|
-
review: false,
|
|
271
|
-
directory: cwd,
|
|
272
|
-
dbUrl,
|
|
273
|
-
})) {
|
|
274
|
-
yield { type: 'ship_event', data: shipEvent };
|
|
275
|
-
if (shipEvent.type === 'done') {
|
|
276
|
-
const shipResult = shipEvent.data;
|
|
277
|
-
totalInputTokens += shipResult.tokensUsed.input;
|
|
278
|
-
totalOutputTokens += shipResult.tokensUsed.output;
|
|
279
|
-
totalCacheCreationTokens += shipResult.tokensUsed.cacheCreation;
|
|
280
|
-
totalCacheReadTokens += shipResult.tokensUsed.cacheRead;
|
|
281
|
-
totalCost += shipResult.cost;
|
|
282
|
-
if (!shipResult.success) {
|
|
283
|
-
// Fix failed, will retry test anyway
|
|
284
|
-
break;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
if (!testSuccess) {
|
|
293
|
-
throw new Error(`Test failed after ${maxRetries} fix attempts`);
|
|
294
|
-
}
|
|
295
|
-
yield { type: 'ticket_phase', data: { phase: 'test', status: 'completed' } };
|
|
296
|
-
}
|
|
297
|
-
else {
|
|
298
|
-
// Implementation ticket - run ship
|
|
299
|
-
yield { type: 'ticket_phase', data: { phase: 'ship', status: 'started' } };
|
|
300
|
-
let shipSuccess = false;
|
|
301
|
-
for await (const event of shipCoreStream({
|
|
302
|
-
ticketData: ticket,
|
|
303
|
-
review,
|
|
304
|
-
directory: cwd,
|
|
305
|
-
dbUrl,
|
|
306
|
-
})) {
|
|
307
|
-
yield { type: 'ship_event', data: event };
|
|
308
|
-
if (event.type === 'done') {
|
|
309
|
-
const shipResult = event.data;
|
|
310
|
-
shipSuccess = shipResult.success;
|
|
311
|
-
totalInputTokens += shipResult.tokensUsed.input;
|
|
312
|
-
totalOutputTokens += shipResult.tokensUsed.output;
|
|
313
|
-
totalCacheCreationTokens += shipResult.tokensUsed.cacheCreation;
|
|
314
|
-
totalCacheReadTokens += shipResult.tokensUsed.cacheRead;
|
|
315
|
-
totalCost += shipResult.cost;
|
|
316
|
-
if (!shipSuccess) {
|
|
317
|
-
throw new Error(shipResult.error || 'Ship failed');
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
yield { type: 'ticket_phase', data: { phase: 'ship', status: 'completed' } };
|
|
322
|
-
// If schema ticket, run migrations
|
|
323
|
-
if (ticket.type === 'schema') {
|
|
324
|
-
yield { type: 'ticket_phase', data: { phase: 'migrate', status: 'started' } };
|
|
325
|
-
let migrateSuccess = false;
|
|
326
|
-
for await (const event of migrateCoreStream({
|
|
327
|
-
directory: cwd,
|
|
328
|
-
dbUrl,
|
|
329
|
-
context: {
|
|
330
|
-
ticketId: ticket.id,
|
|
331
|
-
ticketTitle: ticket.title,
|
|
332
|
-
ticketDescription: ticket.description,
|
|
333
|
-
},
|
|
334
|
-
})) {
|
|
335
|
-
yield { type: 'migrate_event', data: event };
|
|
336
|
-
if (event.type === 'done') {
|
|
337
|
-
const migrateResult = event.data;
|
|
338
|
-
migrateSuccess = migrateResult.success;
|
|
339
|
-
totalInputTokens += migrateResult.tokensUsed.input;
|
|
340
|
-
totalOutputTokens += migrateResult.tokensUsed.output;
|
|
341
|
-
totalCacheCreationTokens += migrateResult.tokensUsed.cacheCreation;
|
|
342
|
-
totalCacheReadTokens += migrateResult.tokensUsed.cacheRead;
|
|
343
|
-
totalCost += migrateResult.cost;
|
|
344
|
-
if (!migrateSuccess) {
|
|
345
|
-
throw new Error(migrateResult.error || 'Migration failed');
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
yield { type: 'ticket_phase', data: { phase: 'migrate', status: 'completed' } };
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
// Ticket succeeded
|
|
353
|
-
updateTicketStatus(ticketsPath, ticket.id, 'Done');
|
|
354
|
-
ticketsSucceeded++;
|
|
355
|
-
yield {
|
|
356
|
-
type: 'ticket_completed',
|
|
357
|
-
data: { ticket, result: 'success' },
|
|
358
|
-
};
|
|
359
|
-
// Auto-commit (no interactive prompts in streaming mode)
|
|
360
|
-
const commitMessage = await commitTicket(ticket, cwd);
|
|
361
|
-
yield {
|
|
362
|
-
type: 'ticket_committed',
|
|
363
|
-
data: { ticket, commitMessage },
|
|
364
|
-
};
|
|
365
|
-
// Yield progress
|
|
366
|
-
yield {
|
|
367
|
-
type: 'progress',
|
|
368
|
-
data: {
|
|
369
|
-
completed: i + 1,
|
|
370
|
-
total: ticketsToProcess.length,
|
|
371
|
-
percentage: Math.round(((i + 1) / ticketsToProcess.length) * 100),
|
|
372
|
-
},
|
|
373
|
-
};
|
|
374
|
-
}
|
|
375
|
-
catch (error) {
|
|
376
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
377
|
-
// Update ticket status to Error
|
|
378
|
-
updateTicketStatus(ticketsPath, ticket.id, 'Error', errorMessage);
|
|
379
|
-
ticketsFailed++;
|
|
380
|
-
yield {
|
|
381
|
-
type: 'ticket_completed',
|
|
382
|
-
data: { ticket, result: 'failed' },
|
|
383
|
-
};
|
|
384
|
-
// Continue to next ticket on failure (don't stop entire build)
|
|
385
|
-
yield {
|
|
386
|
-
type: 'progress',
|
|
387
|
-
data: {
|
|
388
|
-
completed: i + 1,
|
|
389
|
-
total: ticketsToProcess.length,
|
|
390
|
-
percentage: Math.round(((i + 1) / ticketsToProcess.length) * 100),
|
|
391
|
-
},
|
|
392
|
-
};
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
// Yield final result
|
|
396
|
-
yield {
|
|
397
|
-
type: 'done',
|
|
398
|
-
data: {
|
|
399
|
-
success: ticketsFailed === 0,
|
|
400
|
-
ticketsProcessed: ticketsToProcess.length,
|
|
401
|
-
ticketsSucceeded,
|
|
402
|
-
ticketsFailed,
|
|
403
|
-
totalCost,
|
|
404
|
-
tokensUsed: {
|
|
405
|
-
input: totalInputTokens,
|
|
406
|
-
output: totalOutputTokens,
|
|
407
|
-
cacheCreation: totalCacheCreationTokens,
|
|
408
|
-
cacheRead: totalCacheReadTokens,
|
|
409
|
-
},
|
|
410
|
-
},
|
|
411
|
-
};
|
|
412
|
-
}
|
|
413
|
-
/**
|
|
414
|
-
* Main build command - processes all tickets and commits each one
|
|
415
|
-
*/
|
|
416
|
-
export async function buildCommand(options) {
|
|
417
|
-
console.log('🏗️ Starting Build - Batch Ticket Processing\n');
|
|
418
|
-
try {
|
|
419
|
-
// Validate environment
|
|
420
|
-
if (!process.env.ANTHROPIC_API_KEY) {
|
|
421
|
-
throw new Error('ANTHROPIC_API_KEY environment variable is required');
|
|
422
|
-
}
|
|
423
|
-
if (!process.env.GITHUB_TOKEN) {
|
|
424
|
-
throw new Error('GITHUB_TOKEN environment variable is required for build command');
|
|
425
|
-
}
|
|
426
|
-
const { directory, ticketsFile = 'tickets.json', dbUrl = DEFAULT_DB_URL, reset = false, askConfirm = false, askCommit = false, review = true, url, headless, verbose, trace, noLogs = false, } = options;
|
|
427
|
-
// 1. Validate and resolve directory
|
|
428
|
-
const cwd = directory ? resolve(directory) : process.cwd();
|
|
429
|
-
if (!existsSync(cwd)) {
|
|
430
|
-
throw new Error(`Directory not found: ${cwd}\n` +
|
|
431
|
-
`Please provide a valid directory using --directory=<path>\n` +
|
|
432
|
-
`Example: kosuke build --directory=./my-project`);
|
|
433
|
-
}
|
|
434
|
-
const stats = statSync(cwd);
|
|
435
|
-
if (!stats.isDirectory()) {
|
|
436
|
-
throw new Error(`Path is not a directory: ${cwd}\n` + `Please provide a valid directory path.`);
|
|
437
|
-
}
|
|
438
|
-
console.log(`📁 Using project directory: ${cwd}\n`);
|
|
439
|
-
const ticketsPath = join(cwd, ticketsFile);
|
|
440
|
-
// 2. Load tickets
|
|
441
|
-
console.log('📋 Loading tickets...');
|
|
442
|
-
const ticketsData = loadTicketsFile(ticketsPath);
|
|
443
|
-
// 3. Reset all tickets to "Todo" if --reset flag is provided
|
|
444
|
-
if (reset) {
|
|
445
|
-
console.log('🔄 Resetting all tickets to "Todo" status...');
|
|
446
|
-
let resetCount = 0;
|
|
447
|
-
ticketsData.tickets.forEach((ticket) => {
|
|
448
|
-
if (ticket.status !== 'Todo') {
|
|
449
|
-
ticket.status = 'Todo';
|
|
450
|
-
delete ticket.error;
|
|
451
|
-
resetCount++;
|
|
452
|
-
}
|
|
453
|
-
});
|
|
454
|
-
saveTicketsFile(ticketsPath, ticketsData);
|
|
455
|
-
console.log(` ✅ Reset ${resetCount} ticket(s) to "Todo" status\n`);
|
|
456
|
-
}
|
|
457
|
-
const ticketsToProcess = getTicketsToProcess(ticketsData);
|
|
458
|
-
if (ticketsToProcess.length === 0) {
|
|
459
|
-
console.log('ℹ️ No tickets found with status "Todo" or "Error"');
|
|
460
|
-
return;
|
|
461
|
-
}
|
|
462
|
-
console.log(` ✅ Found ${ticketsToProcess.length} ticket(s) to process\n`);
|
|
463
|
-
// Display tickets to be processed
|
|
464
|
-
console.log('📦 Tickets to be processed:');
|
|
465
|
-
ticketsToProcess.forEach((ticket, index) => {
|
|
466
|
-
console.log(` ${index + 1}. ${ticket.id}: ${ticket.title}`);
|
|
467
|
-
});
|
|
468
|
-
console.log('');
|
|
469
|
-
// 4. Process each ticket sequentially
|
|
470
|
-
for (let i = 0; i < ticketsToProcess.length; i++) {
|
|
471
|
-
const ticket = ticketsToProcess[i];
|
|
472
|
-
console.log('\n' + '='.repeat(80));
|
|
473
|
-
console.log(`📦 Processing Ticket ${i + 1}/${ticketsToProcess.length}: ${ticket.id}`);
|
|
474
|
-
console.log(`📝 ${ticket.title}`);
|
|
475
|
-
console.log('='.repeat(80) + '\n');
|
|
476
|
-
try {
|
|
477
|
-
// Step 1: Update status to InProgress
|
|
478
|
-
console.log('📝 Updating ticket status to InProgress...');
|
|
479
|
-
updateTicketStatus(ticketsPath, ticket.id, 'InProgress');
|
|
480
|
-
console.log(' ✅ Status updated\n');
|
|
481
|
-
// Step 2: Process ticket based on type
|
|
482
|
-
const isTestTicket = ticket.type === 'test';
|
|
483
|
-
if (isTestTicket) {
|
|
484
|
-
// This is a test ticket - run test with retry
|
|
485
|
-
console.log(`\n${'='.repeat(60)}`);
|
|
486
|
-
console.log(`🧪 Running Test`);
|
|
487
|
-
console.log(`${'='.repeat(60)}\n`);
|
|
488
|
-
// Generate test prompt from ticket
|
|
489
|
-
const testPrompt = generateWebTestPrompt(ticket);
|
|
490
|
-
let testResult = await testCore({
|
|
491
|
-
prompt: testPrompt,
|
|
492
|
-
context: {
|
|
493
|
-
ticketId: ticket.id,
|
|
494
|
-
ticketTitle: ticket.title,
|
|
495
|
-
ticketDescription: ticket.description,
|
|
496
|
-
},
|
|
497
|
-
url,
|
|
498
|
-
headless,
|
|
499
|
-
verbose,
|
|
500
|
-
trace,
|
|
501
|
-
noLogs,
|
|
502
|
-
});
|
|
503
|
-
let retryCount = 0;
|
|
504
|
-
const maxRetries = 3;
|
|
505
|
-
// Retry loop: if test fails, run ship to fix it
|
|
506
|
-
while (!testResult.success && retryCount < maxRetries) {
|
|
507
|
-
retryCount++;
|
|
508
|
-
console.log(`\n⚠️ Test failed (attempt ${retryCount}/${maxRetries})`);
|
|
509
|
-
console.log(`📝 Error: ${testResult.error}\n`);
|
|
510
|
-
console.log(`🔧 Running ship to fix test failures...\n`);
|
|
511
|
-
// Create a fix ticket for ship
|
|
512
|
-
const fixTicket = {
|
|
513
|
-
id: `${ticket.id}-FIX-${retryCount}`,
|
|
514
|
-
title: `Fix ${ticket.id} test failures`,
|
|
515
|
-
description: `Fix the following test failures:\n\n${testResult.error}\n\nOriginal ticket:\n${ticket.description}`,
|
|
516
|
-
type: 'backend', // Use backend type for test fix tickets
|
|
517
|
-
estimatedEffort: 5,
|
|
518
|
-
status: 'InProgress',
|
|
519
|
-
category: ticket.category,
|
|
520
|
-
};
|
|
521
|
-
const shipResult = await shipCore({
|
|
522
|
-
ticketData: fixTicket,
|
|
523
|
-
review: false, // Skip review for test fixes
|
|
524
|
-
directory: cwd,
|
|
525
|
-
dbUrl,
|
|
526
|
-
noLogs,
|
|
527
|
-
});
|
|
528
|
-
if (!shipResult.success) {
|
|
529
|
-
console.error(`\n❌ Fix attempt ${retryCount} failed: ${shipResult.error}`);
|
|
530
|
-
continue;
|
|
531
|
-
}
|
|
532
|
-
console.log(`\n✅ Fix applied (attempt ${retryCount})`);
|
|
533
|
-
console.log(`💰 Fix cost: $${shipResult.cost.toFixed(4)}\n`);
|
|
534
|
-
// Re-run test
|
|
535
|
-
console.log(`🔄 Re-running test...\n`);
|
|
536
|
-
testResult = await testCore({
|
|
537
|
-
prompt: testPrompt,
|
|
538
|
-
context: {
|
|
539
|
-
ticketId: ticket.id,
|
|
540
|
-
ticketTitle: ticket.title,
|
|
541
|
-
ticketDescription: ticket.description,
|
|
542
|
-
},
|
|
543
|
-
url,
|
|
544
|
-
headless,
|
|
545
|
-
verbose,
|
|
546
|
-
trace,
|
|
547
|
-
noLogs,
|
|
548
|
-
});
|
|
549
|
-
}
|
|
550
|
-
if (!testResult.success) {
|
|
551
|
-
throw new Error(`Test failed after ${maxRetries} fix attempts:\n${testResult.error}`);
|
|
552
|
-
}
|
|
553
|
-
console.log(`\n✅ ${ticket.id} test passed`);
|
|
554
|
-
console.log(`💰 Test cost: $${testResult.cost.toFixed(4)}`);
|
|
555
|
-
}
|
|
556
|
-
else {
|
|
557
|
-
// Regular implementation ticket - run ship
|
|
558
|
-
const shipResult = await shipCore({
|
|
559
|
-
ticketData: ticket,
|
|
560
|
-
review,
|
|
561
|
-
directory: cwd,
|
|
562
|
-
dbUrl,
|
|
563
|
-
noLogs,
|
|
564
|
-
});
|
|
565
|
-
if (!shipResult.success) {
|
|
566
|
-
throw new Error(shipResult.error || 'Ship failed');
|
|
567
|
-
}
|
|
568
|
-
console.log(`\n✅ ${ticket.id} implemented successfully`);
|
|
569
|
-
console.log(`📊 Implementation fixes: ${shipResult.implementationFixCount}`);
|
|
570
|
-
console.log(`🔧 Linting fixes: ${shipResult.lintFixCount}`);
|
|
571
|
-
if (shipResult.reviewFixCount > 0) {
|
|
572
|
-
console.log(`🔍 Review fixes: ${shipResult.reviewFixCount}`);
|
|
573
|
-
}
|
|
574
|
-
console.log(`💰 Ship cost: $${shipResult.cost.toFixed(4)}`);
|
|
575
|
-
// If this is a schema ticket, run migrations
|
|
576
|
-
if (ticket.type === 'schema') {
|
|
577
|
-
console.log(`\n${'='.repeat(60)}`);
|
|
578
|
-
console.log(`🗄️ Phase 4: Database Migration & Validation`);
|
|
579
|
-
console.log(`${'='.repeat(60)}\n`);
|
|
580
|
-
const migrateResult = await migrateCore({
|
|
581
|
-
directory: cwd,
|
|
582
|
-
dbUrl,
|
|
583
|
-
context: {
|
|
584
|
-
ticketId: ticket.id,
|
|
585
|
-
ticketTitle: ticket.title,
|
|
586
|
-
ticketDescription: ticket.description,
|
|
587
|
-
},
|
|
588
|
-
noLogs,
|
|
589
|
-
});
|
|
590
|
-
if (!migrateResult.success) {
|
|
591
|
-
throw new Error(`Migration failed: ${migrateResult.error}`);
|
|
592
|
-
}
|
|
593
|
-
console.log(`\n✅ Migrations applied and validated`);
|
|
594
|
-
console.log(` ✓ Migrations applied: ${migrateResult.migrationsApplied}`);
|
|
595
|
-
console.log(` ✓ Seeding completed: ${migrateResult.seedingCompleted}`);
|
|
596
|
-
console.log(` ✓ Validation passed: ${migrateResult.validationPassed}`);
|
|
597
|
-
console.log(`💰 Migration cost: $${migrateResult.cost.toFixed(4)}`);
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
// Step 3: Update ticket status to Done
|
|
601
|
-
console.log('\n📝 Updating ticket status to Done...');
|
|
602
|
-
updateTicketStatus(ticketsPath, ticket.id, 'Done');
|
|
603
|
-
console.log(` ✅ Ticket ${ticket.id} marked as Done\n`);
|
|
604
|
-
// Step 4: Commit this ticket
|
|
605
|
-
if (askCommit) {
|
|
606
|
-
// Interactive: ask before committing
|
|
607
|
-
const commitConfirmed = await promptConfirmation(`\n❓ Commit ${ticket.id}?`);
|
|
608
|
-
if (commitConfirmed) {
|
|
609
|
-
const commitMessage = await commitTicket(ticket, cwd);
|
|
610
|
-
console.log(`\n ✅ Committed: ${commitMessage}\n`);
|
|
611
|
-
}
|
|
612
|
-
else {
|
|
613
|
-
console.log(' ⏭️ Skipped commit for this ticket\n');
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
else {
|
|
617
|
-
// Default: auto-commit each ticket
|
|
618
|
-
const commitMessage = await commitTicket(ticket, cwd);
|
|
619
|
-
console.log(`\n ✅ Committed: ${commitMessage}\n`);
|
|
620
|
-
}
|
|
621
|
-
// Ask for confirmation before proceeding to next ticket (if not last ticket)
|
|
622
|
-
if (askConfirm && i < ticketsToProcess.length - 1) {
|
|
623
|
-
const shouldContinue = await promptConfirmation('\n❓ Proceed to next ticket?');
|
|
624
|
-
if (!shouldContinue) {
|
|
625
|
-
console.log('\n⏸️ Build paused by user');
|
|
626
|
-
console.log(`📊 Progress: ${i + 1}/${ticketsToProcess.length} tickets completed`);
|
|
627
|
-
console.log('ℹ️ Run build again to resume from remaining tickets\n');
|
|
628
|
-
return;
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
catch (error) {
|
|
633
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
634
|
-
console.error(`\n❌ Failed to process ${ticket.id}: ${errorMessage}`);
|
|
635
|
-
// Update ticket status to Error
|
|
636
|
-
updateTicketStatus(ticketsPath, ticket.id, 'Error', errorMessage);
|
|
637
|
-
console.error('\n❌ Build stopped due to ticket failure');
|
|
638
|
-
console.error('ℹ️ Fix the issue and run build again to resume from failed tickets\n');
|
|
639
|
-
throw error;
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
// 5. Display final summary
|
|
643
|
-
console.log('\n' + '='.repeat(80));
|
|
644
|
-
console.log('✅ Build Completed Successfully!');
|
|
645
|
-
console.log('='.repeat(80));
|
|
646
|
-
console.log(`📦 Total tickets processed: ${ticketsToProcess.length}`);
|
|
647
|
-
console.log(`✅ All tickets have been implemented and committed`);
|
|
648
|
-
console.log('='.repeat(80));
|
|
649
|
-
console.log('\n💡 Next steps:');
|
|
650
|
-
console.log(' - Review the commits: git log');
|
|
651
|
-
console.log(' - Create a PR using: gh pr create');
|
|
652
|
-
console.log(' - Or push to remote: git push origin <branch-name>\n');
|
|
653
|
-
}
|
|
654
|
-
catch (error) {
|
|
655
|
-
console.error('\n❌ Build failed:', error);
|
|
656
|
-
throw error;
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
//# sourceMappingURL=build.js.map
|