@kosuke-ai/cli 0.0.57 → 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 -595
- 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 -37
- 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 -304
- 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 -660
- package/dist/kosuke/commands/build.js.map +0 -1
- package/dist/kosuke/commands/fix.d.ts +0 -21
- package/dist/kosuke/commands/fix.d.ts.map +0 -1
- package/dist/kosuke/commands/fix.js +0 -256
- package/dist/kosuke/commands/fix.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 -248
- 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 -342
- 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 -684
- 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 -414
- 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 -876
- package/dist/kosuke/commands/tickets.js.map +0 -1
- package/dist/kosuke/commands/validate-tickets.d.ts +0 -23
- package/dist/kosuke/commands/validate-tickets.d.ts.map +0 -1
- package/dist/kosuke/commands/validate-tickets.js +0 -360
- package/dist/kosuke/commands/validate-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 -539
- 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 -140
- package/dist/kosuke/utils/claude-agent.d.ts.map +0 -1
- package/dist/kosuke/utils/claude-agent.js +0 -388
- 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/json-parser.d.ts +0 -14
- package/dist/kosuke/utils/json-parser.d.ts.map +0 -1
- package/dist/kosuke/utils/json-parser.js +0 -40
- package/dist/kosuke/utils/json-parser.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 -34
- package/dist/kosuke/utils/tickets-manager.d.ts.map +0 -1
- package/dist/kosuke/utils/tickets-manager.js +0 -106
- 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 -104
- package/dist/lib.d.ts.map +0 -1
- package/dist/lib.js +0 -104
- package/dist/lib.js.map +0 -1
- package/dist/package.json +0 -99
|
@@ -1,684 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plan command - AI-driven ticket planning from feature/bug descriptions
|
|
3
|
-
*
|
|
4
|
-
* This command takes a prompt describing a feature or bug and an existing codebase,
|
|
5
|
-
* asks clarification questions (non-technical, user-focused), and generates tickets.json
|
|
6
|
-
* that can be processed by the build command.
|
|
7
|
-
*
|
|
8
|
-
* Features:
|
|
9
|
-
* - Analyzes existing codebase to understand patterns
|
|
10
|
-
* - Asks AI-generated clarification questions (non-technical)
|
|
11
|
-
* - Auto-detects ticket types (SCHEMA-, BACKEND-, FRONTEND-, TEST-)
|
|
12
|
-
* - Generates tickets.json compatible with build command
|
|
13
|
-
*
|
|
14
|
-
* Usage:
|
|
15
|
-
* kosuke plan --prompt="Add dark mode toggle" --directory=./my-project
|
|
16
|
-
* kosuke plan --prompt="Fix login timeout bug" --dir=./app
|
|
17
|
-
* kosuke plan --prompt="Add notes feature" --no-test # Skip TEST tickets
|
|
18
|
-
*/
|
|
19
|
-
import { existsSync, mkdirSync, statSync } from 'fs';
|
|
20
|
-
import { join, resolve } from 'path';
|
|
21
|
-
import { formatCostBreakdown, logAssistantMessage, logToolUsage, runAgentStream, } from '../utils/claude-agent.js';
|
|
22
|
-
import { askQuestion } from '../utils/interactive-input.js';
|
|
23
|
-
import { extractTicketsJSON } from '../utils/json-parser.js';
|
|
24
|
-
import { logger, setupCancellationHandler } from '../utils/logger.js';
|
|
25
|
-
import { writeTicketsFile } from '../utils/tickets-manager.js';
|
|
26
|
-
/**
|
|
27
|
-
* Sort tickets by processing order (feature-by-feature)
|
|
28
|
-
* Plan command only generates PLAN- prefixed tickets
|
|
29
|
-
*/
|
|
30
|
-
function sortTicketsByOrder(tickets) {
|
|
31
|
-
return [...tickets].sort((a, b) => {
|
|
32
|
-
const getPhaseOrder = (id) => {
|
|
33
|
-
const upper = id.toUpperCase();
|
|
34
|
-
// PLAN batch: schema → engine → backend → frontend → test
|
|
35
|
-
if (upper.startsWith('PLAN-SCHEMA-'))
|
|
36
|
-
return 1;
|
|
37
|
-
if (upper.startsWith('PLAN-ENGINE-'))
|
|
38
|
-
return 2;
|
|
39
|
-
if (upper.startsWith('PLAN-BACKEND-'))
|
|
40
|
-
return 3;
|
|
41
|
-
if (upper.startsWith('PLAN-FRONTEND-'))
|
|
42
|
-
return 4;
|
|
43
|
-
if (upper.startsWith('PLAN-TEST-'))
|
|
44
|
-
return 5;
|
|
45
|
-
return 6; // Any other ticket types (shouldn't happen)
|
|
46
|
-
};
|
|
47
|
-
return getPhaseOrder(a.id) - getPhaseOrder(b.id);
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Generate timestamp-based tickets path in tickets/ folder
|
|
52
|
-
* Creates the tickets/ folder if it doesn't exist
|
|
53
|
-
*/
|
|
54
|
-
function generateTicketsPath(cwd) {
|
|
55
|
-
const ticketsDir = join(cwd, 'tickets');
|
|
56
|
-
// Create tickets folder if it doesn't exist
|
|
57
|
-
if (!existsSync(ticketsDir)) {
|
|
58
|
-
mkdirSync(ticketsDir, { recursive: true });
|
|
59
|
-
}
|
|
60
|
-
// Generate timestamp: YYYY-MM-DD-HH-mm-ss
|
|
61
|
-
const now = new Date();
|
|
62
|
-
const timestamp = now
|
|
63
|
-
.toISOString()
|
|
64
|
-
.replace(/[T:]/g, '-')
|
|
65
|
-
.replace(/\.\d{3}Z$/, '');
|
|
66
|
-
return join(ticketsDir, `${timestamp}.tickets.json`);
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Build system prompt for plan command
|
|
70
|
-
*
|
|
71
|
-
* Two-phase workflow:
|
|
72
|
-
* - Phase 1: Ask clarification questions (non-technical, user-focused)
|
|
73
|
-
* - Phase 2: Generate tickets via write_tickets tool
|
|
74
|
-
*
|
|
75
|
-
* @param noTest - If true, exclude TEST tickets from generation
|
|
76
|
-
*/
|
|
77
|
-
function buildPlanSystemPrompt(noTest = false) {
|
|
78
|
-
const testGuidelines = noTest
|
|
79
|
-
? ''
|
|
80
|
-
: `
|
|
81
|
-
|
|
82
|
-
**E2E Test Tickets:**
|
|
83
|
-
- Find test users in seed files (\`lib/db/seed.ts\`)
|
|
84
|
-
- Pattern: \`*+kosuke_test@example.com\` → OTP: \`424242\`
|
|
85
|
-
- Required: Test credentials, numbered steps, clear element descriptions, acceptance criteria`;
|
|
86
|
-
return `# ROLE: TICKET PLANNER
|
|
87
|
-
|
|
88
|
-
**YOUR PRIMARY OBJECTIVE:** Create implementation tickets that developers will use to build the feature. You analyze requirements and break them into structured, actionable tickets.
|
|
89
|
-
|
|
90
|
-
**Your Workflow:**
|
|
91
|
-
|
|
92
|
-
**Phase 1:** Ask clarification questions (non-technical, user-focused)
|
|
93
|
-
**Phase 2:** Output raw JSON tickets array
|
|
94
|
-
|
|
95
|
-
**Critical Rules:**
|
|
96
|
-
- NEVER start implementation - you only create tickets
|
|
97
|
-
- NEVER create/edit files, install packages, or use Task tool
|
|
98
|
-
- ALWAYS explore codebase (Read/Grep/Glob) to understand patterns before asking questions
|
|
99
|
-
- YOU decide technical implementation details based on existing codebase
|
|
100
|
-
|
|
101
|
-
## Phase 1: Ask Clarification Questions
|
|
102
|
-
|
|
103
|
-
When a user describes a feature request, analyze the codebase (Read/Grep/Glob) to understand existing patterns, then ask **ONLY business/UX questions** (not technical implementation questions).
|
|
104
|
-
|
|
105
|
-
**Your first response MUST use this exact format:**
|
|
106
|
-
|
|
107
|
-
---
|
|
108
|
-
## Understanding Your Request
|
|
109
|
-
[Brief business summary - what the user wants to achieve, NOT implementation details]
|
|
110
|
-
|
|
111
|
-
## Clarification Questions
|
|
112
|
-
|
|
113
|
-
For each clarification needed, provide BOTH a question AND a recommended approach:
|
|
114
|
-
|
|
115
|
-
1. **[Topic]**
|
|
116
|
-
- Question: [Non-technical user question]
|
|
117
|
-
- 💡 Recommendation: [Default choice that simplifies scope]
|
|
118
|
-
|
|
119
|
-
2. **[Topic]**
|
|
120
|
-
- Question: [Non-technical user question]
|
|
121
|
-
- 💡 Recommendation: [Default choice that simplifies scope]
|
|
122
|
-
|
|
123
|
-
(Add as many questions as needed)
|
|
124
|
-
|
|
125
|
-
**Quick Response Option:** You can reply "go for recommendations" to accept all recommended approaches at once.
|
|
126
|
-
---
|
|
127
|
-
|
|
128
|
-
**ALLOWED QUESTIONS (User/Business Focus):**
|
|
129
|
-
- What data to show/hide, empty state behavior
|
|
130
|
-
- Error messages users see
|
|
131
|
-
- Permission rules (who can do what)
|
|
132
|
-
- User workflow and steps
|
|
133
|
-
|
|
134
|
-
**FORBIDDEN QUESTIONS (Technical - YOU decide these):**
|
|
135
|
-
- Which library to use (jsPDF, PDFKit, etc.)
|
|
136
|
-
- Backend vs client-side generation
|
|
137
|
-
- API design (REST, tRPC, GraphQL)
|
|
138
|
-
- Database queries or ORM choice
|
|
139
|
-
- Component structure or styling
|
|
140
|
-
- Performance optimization techniques
|
|
141
|
-
|
|
142
|
-
**YOU decide all technical choices** based on existing codebase patterns.
|
|
143
|
-
|
|
144
|
-
**Language Reminders:**
|
|
145
|
-
- ⚠️ NEVER say: "I'll implement", "Let me build", "Now I'll create the files"
|
|
146
|
-
- ✅ INSTEAD say: "I'll create tickets for", "The tickets will include"
|
|
147
|
-
|
|
148
|
-
## Phase 2: Generate Tickets
|
|
149
|
-
|
|
150
|
-
Once the user answers questions OR says "go for recommendations", immediately output a raw JSON array of tickets.
|
|
151
|
-
|
|
152
|
-
**Critical:**
|
|
153
|
-
- DO NOT say "Now I'll implement" or show "Implementation Plan" - you're creating TICKETS, not implementing
|
|
154
|
-
- DO NOT read more files after Phase 1 completes
|
|
155
|
-
- Your ENTIRE response = JSON array (no markdown wrapping, no explanations)
|
|
156
|
-
- Output starts with "[" and ends with "]"
|
|
157
|
-
|
|
158
|
-
**Required JSON Format:**
|
|
159
|
-
[
|
|
160
|
-
{
|
|
161
|
-
"id": "PLAN-BACKEND-1",
|
|
162
|
-
"title": "Add PDF export endpoint to orders router",
|
|
163
|
-
"description": "Create tRPC endpoint that generates PDF.\\n\\n**Acceptance Criteria:**\\n- Accepts filter parameters\\n- Returns PDF file\\n- Respects filters",
|
|
164
|
-
"type": "backend",
|
|
165
|
-
"estimatedEffort": 5,
|
|
166
|
-
"status": "Todo",
|
|
167
|
-
"category": "orders"
|
|
168
|
-
},
|
|
169
|
-
{
|
|
170
|
-
"id": "PLAN-FRONTEND-1",
|
|
171
|
-
"title": "Add PDF export button to orders table",
|
|
172
|
-
"description": "Add button to toolbar.\\n\\n**Acceptance Criteria:**\\n- Button visible\\n- Downloads PDF\\n- Shows loading state",
|
|
173
|
-
"type": "frontend",
|
|
174
|
-
"estimatedEffort": 4,
|
|
175
|
-
"status": "Todo",
|
|
176
|
-
"category": "orders"
|
|
177
|
-
}${noTest
|
|
178
|
-
? ''
|
|
179
|
-
: `,
|
|
180
|
-
{
|
|
181
|
-
"id": "PLAN-TEST-1",
|
|
182
|
-
"title": "E2E: Test PDF export with filters",
|
|
183
|
-
"description": "**Test User:** john+kosuke_test@example.com (OTP: 424242)\\n\\n**Steps:**\\n1. Sign in\\n2. Apply filters\\n3. Click PDF export\\n4. Verify download\\n\\n**Acceptance Criteria:**\\n- PDF downloads\\n- Contains filtered data",
|
|
184
|
-
"type": "test",
|
|
185
|
-
"estimatedEffort": 3,
|
|
186
|
-
"status": "Todo",
|
|
187
|
-
"category": "orders"
|
|
188
|
-
}`}
|
|
189
|
-
]
|
|
190
|
-
|
|
191
|
-
**CRITICAL - Exact Ticket ID Format (MUST MATCH):**
|
|
192
|
-
- PLAN-SCHEMA-1, PLAN-SCHEMA-2, ... → type: "schema"
|
|
193
|
-
- PLAN-ENGINE-1, PLAN-ENGINE-2, ... → type: "engine"
|
|
194
|
-
- PLAN-BACKEND-1, PLAN-BACKEND-2, ... → type: "backend"
|
|
195
|
-
- PLAN-FRONTEND-1, PLAN-FRONTEND-2, ... → type: "frontend"${noTest ? '' : '\n- PLAN-TEST-1, PLAN-TEST-2, ... → type: "test"'}
|
|
196
|
-
|
|
197
|
-
**Required Fields (every ticket):**
|
|
198
|
-
- id: Exact format above (e.g., "PLAN-TEST-1")
|
|
199
|
-
- title: Short descriptive title
|
|
200
|
-
- description: Details with **Acceptance Criteria:** section (use \\n for newlines)
|
|
201
|
-
- type: MUST be one of: "schema", "engine", "backend", "frontend"${noTest ? '' : ', "test"'}
|
|
202
|
-
- estimatedEffort: Integer from 1 to 10
|
|
203
|
-
- status: ALWAYS "Todo"
|
|
204
|
-
- category: Optional (e.g., "orders", "auth", "billing")
|
|
205
|
-
|
|
206
|
-
**Dependency order:** SCHEMA → ENGINE → BACKEND → FRONTEND${noTest ? '' : ' → TEST'}
|
|
207
|
-
${testGuidelines}
|
|
208
|
-
|
|
209
|
-
🚨 **WHEN USER SAYS "go for recommendations" OR ANSWERS YOUR QUESTIONS:**
|
|
210
|
-
|
|
211
|
-
YOU ARE NOW IN PHASE 2. EXPLORATION IS OVER.
|
|
212
|
-
|
|
213
|
-
DO NOT:
|
|
214
|
-
- Read more files
|
|
215
|
-
- Search for packages
|
|
216
|
-
- Say "Now I'll implement" or "Let me create"
|
|
217
|
-
- Use Task tool
|
|
218
|
-
- Show "Implementation Plan"
|
|
219
|
-
- Add any text before or after the JSON
|
|
220
|
-
|
|
221
|
-
IMMEDIATELY OUTPUT THE JSON ARRAY. Your ENTIRE response = JSON array starting with "[" and ending with "]".
|
|
222
|
-
|
|
223
|
-
**Examples:**
|
|
224
|
-
|
|
225
|
-
❌ WRONG: \`Perfect! Now I'll implement... [shows implementation plan]\`
|
|
226
|
-
❌ WRONG: \`Great! I'll create the tickets. \\\`\\\`\\\`json [...] \\\`\\\`\\\`\` (markdown wrapping)
|
|
227
|
-
❌ WRONG: \`Now I'll update the files...\`
|
|
228
|
-
|
|
229
|
-
✅ CORRECT: \`[{"id": "PLAN-BACKEND-1", "title": "Add PDF export endpoint", ...}]\`
|
|
230
|
-
|
|
231
|
-
Just the raw JSON array. No explanatory text. No markdown code fences. No "Now I'll implement" language.`;
|
|
232
|
-
}
|
|
233
|
-
/**
|
|
234
|
-
* Shared setup for plan agent configuration
|
|
235
|
-
*/
|
|
236
|
-
function createPlanAgentConfig(options) {
|
|
237
|
-
const { prompt, directory, noTest = false, resume } = options;
|
|
238
|
-
// Validate directory
|
|
239
|
-
const cwd = directory ? resolve(directory) : process.cwd();
|
|
240
|
-
if (!existsSync(cwd)) {
|
|
241
|
-
return { error: `Directory not found: ${cwd}` };
|
|
242
|
-
}
|
|
243
|
-
const stats = statSync(cwd);
|
|
244
|
-
if (!stats.isDirectory()) {
|
|
245
|
-
return { error: `Path is not a directory: ${cwd}` };
|
|
246
|
-
}
|
|
247
|
-
const ticketsPath = generateTicketsPath(cwd);
|
|
248
|
-
const systemPrompt = buildPlanSystemPrompt(noTest);
|
|
249
|
-
const config = {
|
|
250
|
-
systemPrompt,
|
|
251
|
-
cwd,
|
|
252
|
-
maxTurns: 40, // Increased for complex planning sessions with multiple files to analyze
|
|
253
|
-
verbosity: 'verbose',
|
|
254
|
-
permissionMode: 'bypassPermissions',
|
|
255
|
-
// Restrict to read-only tools only
|
|
256
|
-
// Block all code editing, execution, task management, and agent control tools
|
|
257
|
-
disallowedTools: [
|
|
258
|
-
'Edit', // File editing
|
|
259
|
-
'Write', // File creation
|
|
260
|
-
'Delete', // File deletion
|
|
261
|
-
'NotebookEdit', // Notebook editing
|
|
262
|
-
'Bash', // Shell execution
|
|
263
|
-
'Task', // Sub-agent spawning (prevents implementation subtasks)
|
|
264
|
-
'TodoWrite', // Task management (implementation mode)
|
|
265
|
-
'ExitPlanMode', // Mode transitions
|
|
266
|
-
],
|
|
267
|
-
...(resume && { resume }),
|
|
268
|
-
};
|
|
269
|
-
return { config, ticketsPath, cwd, prompt };
|
|
270
|
-
}
|
|
271
|
-
/**
|
|
272
|
-
* Plan core stream for server (async generator, no logging)
|
|
273
|
-
*/
|
|
274
|
-
export async function* planCoreStream(options) {
|
|
275
|
-
const setup = createPlanAgentConfig(options);
|
|
276
|
-
if ('error' in setup) {
|
|
277
|
-
yield {
|
|
278
|
-
type: 'done',
|
|
279
|
-
data: {
|
|
280
|
-
status: 'error',
|
|
281
|
-
ticketsFile: null,
|
|
282
|
-
tokensUsed: { input: 0, output: 0, cacheCreation: 0, cacheRead: 0 },
|
|
283
|
-
cost: 0,
|
|
284
|
-
error: setup.error,
|
|
285
|
-
},
|
|
286
|
-
};
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
const { config, ticketsPath, prompt } = setup;
|
|
290
|
-
try {
|
|
291
|
-
const stream = runAgentStream(prompt, config);
|
|
292
|
-
let sessionId;
|
|
293
|
-
let fullResponse = '';
|
|
294
|
-
let tokensUsed = { input: 0, output: 0, cacheCreation: 0, cacheRead: 0 };
|
|
295
|
-
let cost = 0;
|
|
296
|
-
// Yield events from stream
|
|
297
|
-
for await (const event of stream) {
|
|
298
|
-
if (event.type === 'message') {
|
|
299
|
-
const claudeMessage = event.data;
|
|
300
|
-
yield { type: 'message', data: claudeMessage };
|
|
301
|
-
// Track session ID
|
|
302
|
-
if (claudeMessage.session_id) {
|
|
303
|
-
sessionId = claudeMessage.session_id;
|
|
304
|
-
}
|
|
305
|
-
// Accumulate response text and extract tool calls from assistant messages
|
|
306
|
-
if (claudeMessage.type === 'assistant' && claudeMessage.message) {
|
|
307
|
-
const msg = claudeMessage.message;
|
|
308
|
-
if (msg.content && Array.isArray(msg.content)) {
|
|
309
|
-
for (const block of msg.content) {
|
|
310
|
-
if (block.type === 'text' && block.text) {
|
|
311
|
-
fullResponse += block.text;
|
|
312
|
-
}
|
|
313
|
-
else if (block.type === 'tool_use' && block.name) {
|
|
314
|
-
// Yield tool call event
|
|
315
|
-
yield {
|
|
316
|
-
type: 'tool_call',
|
|
317
|
-
data: { name: block.name, input: block.input || {} },
|
|
318
|
-
};
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
else if (event.type === 'agent_result') {
|
|
325
|
-
// Use metrics from final result
|
|
326
|
-
tokensUsed = event.data.tokensUsed;
|
|
327
|
-
cost = event.data.cost;
|
|
328
|
-
if (event.data.sessionId) {
|
|
329
|
-
sessionId = event.data.sessionId;
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
// Try to parse tickets from response (Phase 2)
|
|
334
|
-
try {
|
|
335
|
-
const tickets = extractTicketsJSON(fullResponse);
|
|
336
|
-
// If no tickets were parsed, this is Phase 1 (clarification questions)
|
|
337
|
-
if (!tickets || tickets.length === 0) {
|
|
338
|
-
yield {
|
|
339
|
-
type: 'done',
|
|
340
|
-
data: {
|
|
341
|
-
status: 'input_required',
|
|
342
|
-
ticketsFile: null,
|
|
343
|
-
tokensUsed,
|
|
344
|
-
cost,
|
|
345
|
-
sessionId,
|
|
346
|
-
},
|
|
347
|
-
};
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
350
|
-
// Sort and write tickets (no validation, no summary in stream mode)
|
|
351
|
-
const sortedTickets = sortTicketsByOrder(tickets);
|
|
352
|
-
writeTicketsFile(ticketsPath, sortedTickets);
|
|
353
|
-
yield {
|
|
354
|
-
type: 'done',
|
|
355
|
-
data: {
|
|
356
|
-
status: 'success',
|
|
357
|
-
ticketsFile: ticketsPath,
|
|
358
|
-
tokensUsed,
|
|
359
|
-
cost,
|
|
360
|
-
sessionId,
|
|
361
|
-
},
|
|
362
|
-
};
|
|
363
|
-
}
|
|
364
|
-
catch (parseError) {
|
|
365
|
-
const errorMsg = parseError instanceof Error ? parseError.message : String(parseError);
|
|
366
|
-
// Check if this is a parse/validation error or just Phase 1
|
|
367
|
-
if (errorMsg.includes('No JSON array found')) {
|
|
368
|
-
// This is Phase 1 (clarification questions)
|
|
369
|
-
yield {
|
|
370
|
-
type: 'done',
|
|
371
|
-
data: {
|
|
372
|
-
status: 'input_required',
|
|
373
|
-
ticketsFile: null,
|
|
374
|
-
tokensUsed,
|
|
375
|
-
cost,
|
|
376
|
-
sessionId,
|
|
377
|
-
},
|
|
378
|
-
};
|
|
379
|
-
}
|
|
380
|
-
else {
|
|
381
|
-
// Actual validation error
|
|
382
|
-
yield {
|
|
383
|
-
type: 'done',
|
|
384
|
-
data: {
|
|
385
|
-
status: 'error',
|
|
386
|
-
ticketsFile: null,
|
|
387
|
-
tokensUsed,
|
|
388
|
-
cost: 0,
|
|
389
|
-
error: errorMsg,
|
|
390
|
-
},
|
|
391
|
-
};
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
catch (error) {
|
|
396
|
-
yield {
|
|
397
|
-
type: 'done',
|
|
398
|
-
data: {
|
|
399
|
-
status: 'error',
|
|
400
|
-
ticketsFile: null,
|
|
401
|
-
tokensUsed: { input: 0, output: 0, cacheCreation: 0, cacheRead: 0 },
|
|
402
|
-
cost: 0,
|
|
403
|
-
error: error instanceof Error ? error.message : String(error),
|
|
404
|
-
},
|
|
405
|
-
};
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
/**
|
|
409
|
-
* Plan interactive session for CLI (single turn with logging)
|
|
410
|
-
*/
|
|
411
|
-
async function planInteractiveSession(options) {
|
|
412
|
-
const setup = createPlanAgentConfig(options);
|
|
413
|
-
if ('error' in setup) {
|
|
414
|
-
return {
|
|
415
|
-
status: 'error',
|
|
416
|
-
ticketsFile: null,
|
|
417
|
-
tokensUsed: { input: 0, output: 0, cacheCreation: 0, cacheRead: 0 },
|
|
418
|
-
cost: 0,
|
|
419
|
-
error: setup.error,
|
|
420
|
-
};
|
|
421
|
-
}
|
|
422
|
-
const { config, ticketsPath, prompt } = setup;
|
|
423
|
-
try {
|
|
424
|
-
console.log('\n🤔 Claude is analyzing...\n');
|
|
425
|
-
// Run agent with streaming
|
|
426
|
-
const stream = runAgentStream(prompt, config);
|
|
427
|
-
let response = '';
|
|
428
|
-
let tokensUsed = { input: 0, output: 0, cacheCreation: 0, cacheRead: 0 };
|
|
429
|
-
let cost = 0;
|
|
430
|
-
let sessionId;
|
|
431
|
-
// Process stream
|
|
432
|
-
const filesReferenced = new Set();
|
|
433
|
-
for await (const event of stream) {
|
|
434
|
-
if (event.type === 'message') {
|
|
435
|
-
const message = event.data;
|
|
436
|
-
if (message.type === 'assistant' && message.message?.content) {
|
|
437
|
-
for (const block of message.message.content) {
|
|
438
|
-
if (block.type === 'text' && block.text) {
|
|
439
|
-
logAssistantMessage(block.text, 'verbose');
|
|
440
|
-
}
|
|
441
|
-
else if (block.type === 'tool_use' && block.name) {
|
|
442
|
-
logToolUsage(block.name, block.input, filesReferenced);
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
else if (event.type === 'agent_result') {
|
|
448
|
-
response = event.data.response;
|
|
449
|
-
tokensUsed = event.data.tokensUsed;
|
|
450
|
-
cost = event.data.cost;
|
|
451
|
-
sessionId = event.data.sessionId;
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
// Display cost
|
|
455
|
-
console.log('\n' + '─'.repeat(90));
|
|
456
|
-
console.log(`💰 Cost: ${formatCostBreakdown({
|
|
457
|
-
tokensUsed,
|
|
458
|
-
cost,
|
|
459
|
-
response: '',
|
|
460
|
-
fixCount: 0,
|
|
461
|
-
filesReferenced: new Set(),
|
|
462
|
-
})}`);
|
|
463
|
-
console.log('─'.repeat(90) + '\n');
|
|
464
|
-
// Try to parse tickets from response (Phase 2)
|
|
465
|
-
try {
|
|
466
|
-
const tickets = extractTicketsJSON(response);
|
|
467
|
-
// If no tickets were parsed, this is Phase 1 (clarification questions)
|
|
468
|
-
if (!tickets || tickets.length === 0) {
|
|
469
|
-
return {
|
|
470
|
-
status: 'input_required',
|
|
471
|
-
ticketsFile: null,
|
|
472
|
-
tokensUsed,
|
|
473
|
-
cost,
|
|
474
|
-
sessionId,
|
|
475
|
-
message: response,
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
// Sort and write tickets (no validation, no summary)
|
|
479
|
-
const sortedTickets = sortTicketsByOrder(tickets);
|
|
480
|
-
writeTicketsFile(ticketsPath, sortedTickets);
|
|
481
|
-
console.log(`\n✅ Successfully created ${tickets.length} tickets: ${ticketsPath}\n`);
|
|
482
|
-
return {
|
|
483
|
-
status: 'success',
|
|
484
|
-
ticketsFile: ticketsPath,
|
|
485
|
-
tokensUsed,
|
|
486
|
-
cost,
|
|
487
|
-
sessionId,
|
|
488
|
-
message: response,
|
|
489
|
-
};
|
|
490
|
-
}
|
|
491
|
-
catch (parseError) {
|
|
492
|
-
const errorMsg = parseError instanceof Error ? parseError.message : String(parseError);
|
|
493
|
-
// Check if this is a parse/validation error or just Phase 1
|
|
494
|
-
if (errorMsg.includes('No JSON array found')) {
|
|
495
|
-
// This is Phase 1 (clarification questions)
|
|
496
|
-
return {
|
|
497
|
-
status: 'input_required',
|
|
498
|
-
ticketsFile: null,
|
|
499
|
-
tokensUsed,
|
|
500
|
-
cost,
|
|
501
|
-
sessionId,
|
|
502
|
-
message: response,
|
|
503
|
-
};
|
|
504
|
-
}
|
|
505
|
-
// Actual validation error - show it
|
|
506
|
-
console.error(`\n❌ Ticket validation failed: ${errorMsg}\n`);
|
|
507
|
-
return {
|
|
508
|
-
status: 'error',
|
|
509
|
-
ticketsFile: null,
|
|
510
|
-
tokensUsed,
|
|
511
|
-
cost,
|
|
512
|
-
error: errorMsg,
|
|
513
|
-
};
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
catch (error) {
|
|
517
|
-
return {
|
|
518
|
-
status: 'error',
|
|
519
|
-
ticketsFile: null,
|
|
520
|
-
tokensUsed: { input: 0, output: 0, cacheCreation: 0, cacheRead: 0 },
|
|
521
|
-
cost: 0,
|
|
522
|
-
error: error instanceof Error ? error.message : String(error),
|
|
523
|
-
};
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
/**
|
|
527
|
-
* Main plan command (interactive CLI wrapper)
|
|
528
|
-
*/
|
|
529
|
-
export async function planCommand(options) {
|
|
530
|
-
// Initialize logging
|
|
531
|
-
const logContext = logger.createContext('plan', { noLogs: options.noLogs ?? false });
|
|
532
|
-
const cleanupHandler = setupCancellationHandler(logContext);
|
|
533
|
-
try {
|
|
534
|
-
// Validate environment
|
|
535
|
-
if (!process.env.ANTHROPIC_API_KEY) {
|
|
536
|
-
throw new Error('ANTHROPIC_API_KEY environment variable is required');
|
|
537
|
-
}
|
|
538
|
-
// Validate prompt
|
|
539
|
-
if (!options.prompt) {
|
|
540
|
-
throw new Error('Prompt is required. Use --prompt="Your feature or bug description"\n' +
|
|
541
|
-
'Example: kosuke plan --prompt="Add dark mode toggle" --directory=./my-project');
|
|
542
|
-
}
|
|
543
|
-
// Resolve directory
|
|
544
|
-
const cwd = options.directory ? resolve(options.directory) : process.cwd();
|
|
545
|
-
if (!existsSync(cwd)) {
|
|
546
|
-
throw new Error(`Directory not found: ${cwd}`);
|
|
547
|
-
}
|
|
548
|
-
const stats = statSync(cwd);
|
|
549
|
-
if (!stats.isDirectory()) {
|
|
550
|
-
throw new Error(`Path is not a directory: ${cwd}`);
|
|
551
|
-
}
|
|
552
|
-
console.log(`
|
|
553
|
-
╔══════════════════════════════════════════════════════════════════════════════╗
|
|
554
|
-
║ Kosuke Plan - AI-Driven Ticket Planning ║
|
|
555
|
-
╚══════════════════════════════════════════════════════════════════════════════╝
|
|
556
|
-
`);
|
|
557
|
-
console.log('💡 This tool will help you create implementation tickets from your feature/bug description.\n');
|
|
558
|
-
console.log('🤖 Claude will explore your codebase to understand patterns and conventions.\n');
|
|
559
|
-
console.log('✨ Tip: Enter to submit, Ctrl+J for new lines.\n');
|
|
560
|
-
console.log(`📁 Using project directory: ${cwd}\n`);
|
|
561
|
-
// Set up Ctrl+C handler
|
|
562
|
-
const handleSigInt = async () => {
|
|
563
|
-
console.log('\n\n👋 Exiting planning session...\n');
|
|
564
|
-
await logger.complete(logContext, 'cancelled');
|
|
565
|
-
cleanupHandler();
|
|
566
|
-
process.exit(0);
|
|
567
|
-
};
|
|
568
|
-
process.on('SIGINT', handleSigInt);
|
|
569
|
-
let currentPrompt = options.prompt;
|
|
570
|
-
let sessionId = options.resume;
|
|
571
|
-
let totalInputTokens = 0;
|
|
572
|
-
let totalOutputTokens = 0;
|
|
573
|
-
let totalCacheCreationTokens = 0;
|
|
574
|
-
let totalCacheReadTokens = 0;
|
|
575
|
-
let totalCost = 0;
|
|
576
|
-
try {
|
|
577
|
-
// Interactive loop
|
|
578
|
-
while (true) {
|
|
579
|
-
const result = await planInteractiveSession({
|
|
580
|
-
prompt: currentPrompt,
|
|
581
|
-
directory: cwd,
|
|
582
|
-
noTest: options.noTest,
|
|
583
|
-
resume: sessionId,
|
|
584
|
-
});
|
|
585
|
-
// Track cumulative costs
|
|
586
|
-
totalInputTokens += result.tokensUsed.input;
|
|
587
|
-
totalOutputTokens += result.tokensUsed.output;
|
|
588
|
-
totalCacheCreationTokens += result.tokensUsed.cacheCreation;
|
|
589
|
-
totalCacheReadTokens += result.tokensUsed.cacheRead;
|
|
590
|
-
totalCost += result.cost;
|
|
591
|
-
sessionId = result.sessionId;
|
|
592
|
-
if (result.status === 'success') {
|
|
593
|
-
// Planning complete
|
|
594
|
-
console.log('═'.repeat(90));
|
|
595
|
-
console.log('📊 Total Session Cost:');
|
|
596
|
-
console.log(`💰 ${formatCostBreakdown({
|
|
597
|
-
tokensUsed: {
|
|
598
|
-
input: totalInputTokens,
|
|
599
|
-
output: totalOutputTokens,
|
|
600
|
-
cacheCreation: totalCacheCreationTokens,
|
|
601
|
-
cacheRead: totalCacheReadTokens,
|
|
602
|
-
},
|
|
603
|
-
cost: totalCost,
|
|
604
|
-
response: '',
|
|
605
|
-
fixCount: 0,
|
|
606
|
-
filesReferenced: new Set(),
|
|
607
|
-
})}`);
|
|
608
|
-
console.log('═'.repeat(90));
|
|
609
|
-
const relativeTicketsPath = result.ticketsFile.replace(cwd + '/', '');
|
|
610
|
-
console.log('\n🎉 Planning complete!\n');
|
|
611
|
-
console.log('💡 Next steps:');
|
|
612
|
-
console.log(' - Review tickets: cat "' + result.ticketsFile + '"');
|
|
613
|
-
console.log(' - Build tickets: kosuke build --directory="' +
|
|
614
|
-
cwd +
|
|
615
|
-
'" --tickets="' +
|
|
616
|
-
relativeTicketsPath +
|
|
617
|
-
'"');
|
|
618
|
-
console.log(' - List all tickets: ls ' + join(cwd, 'tickets'));
|
|
619
|
-
if (sessionId) {
|
|
620
|
-
console.log(`\n💾 Session ID: ${sessionId}`);
|
|
621
|
-
}
|
|
622
|
-
logger.trackTokens(logContext, {
|
|
623
|
-
input: totalInputTokens,
|
|
624
|
-
output: totalOutputTokens,
|
|
625
|
-
cacheCreation: totalCacheCreationTokens,
|
|
626
|
-
cacheRead: totalCacheReadTokens,
|
|
627
|
-
});
|
|
628
|
-
await logger.complete(logContext, 'success');
|
|
629
|
-
break;
|
|
630
|
-
}
|
|
631
|
-
else if (result.status === 'input_required') {
|
|
632
|
-
// Ask for user response
|
|
633
|
-
console.log('💬 Your response (type "exit" to quit):\n');
|
|
634
|
-
const userResponse = await askQuestion('You: ');
|
|
635
|
-
if (!userResponse) {
|
|
636
|
-
console.log('\n⚠️ Empty response. Please provide an answer or type "exit".');
|
|
637
|
-
continue;
|
|
638
|
-
}
|
|
639
|
-
if (userResponse.toLowerCase() === 'exit') {
|
|
640
|
-
console.log('\n👋 Exiting planning session.\n');
|
|
641
|
-
if (sessionId) {
|
|
642
|
-
console.log('💾 Session ID (to resume later):');
|
|
643
|
-
console.log(` ${sessionId}\n`);
|
|
644
|
-
console.log(' Resume with: kosuke plan --prompt="continue" --resume=' + sessionId + '\n');
|
|
645
|
-
}
|
|
646
|
-
console.log('═'.repeat(90));
|
|
647
|
-
console.log('📊 Session Cost:');
|
|
648
|
-
console.log(`💰 ${formatCostBreakdown({
|
|
649
|
-
tokensUsed: {
|
|
650
|
-
input: totalInputTokens,
|
|
651
|
-
output: totalOutputTokens,
|
|
652
|
-
cacheCreation: totalCacheCreationTokens,
|
|
653
|
-
cacheRead: totalCacheReadTokens,
|
|
654
|
-
},
|
|
655
|
-
cost: totalCost,
|
|
656
|
-
response: '',
|
|
657
|
-
fixCount: 0,
|
|
658
|
-
filesReferenced: new Set(),
|
|
659
|
-
})}`);
|
|
660
|
-
console.log('═'.repeat(90) + '\n');
|
|
661
|
-
await logger.complete(logContext, 'cancelled');
|
|
662
|
-
break;
|
|
663
|
-
}
|
|
664
|
-
currentPrompt = userResponse;
|
|
665
|
-
}
|
|
666
|
-
else {
|
|
667
|
-
// Error
|
|
668
|
-
throw new Error(result.error || 'Unknown error during planning');
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
finally {
|
|
673
|
-
process.removeListener('SIGINT', handleSigInt);
|
|
674
|
-
}
|
|
675
|
-
cleanupHandler();
|
|
676
|
-
}
|
|
677
|
-
catch (error) {
|
|
678
|
-
console.error('\n❌ Plan command failed:', error);
|
|
679
|
-
await logger.complete(logContext, 'error', error);
|
|
680
|
-
cleanupHandler();
|
|
681
|
-
throw error;
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
//# sourceMappingURL=plan.js.map
|