gencode-ai 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/README.md +15 -17
  2. package/dist/agent/agent.d.ts +43 -0
  3. package/dist/agent/agent.d.ts.map +1 -1
  4. package/dist/agent/agent.js +107 -4
  5. package/dist/agent/agent.js.map +1 -1
  6. package/dist/agent/index.d.ts +1 -0
  7. package/dist/agent/index.d.ts.map +1 -1
  8. package/dist/agent/types.d.ts +20 -1
  9. package/dist/agent/types.d.ts.map +1 -1
  10. package/dist/checkpointing/checkpoint-manager.d.ts +87 -0
  11. package/dist/checkpointing/checkpoint-manager.d.ts.map +1 -0
  12. package/dist/checkpointing/checkpoint-manager.js +281 -0
  13. package/dist/checkpointing/checkpoint-manager.js.map +1 -0
  14. package/dist/checkpointing/index.d.ts +29 -0
  15. package/dist/checkpointing/index.d.ts.map +1 -0
  16. package/dist/checkpointing/index.js +29 -0
  17. package/dist/checkpointing/index.js.map +1 -0
  18. package/dist/checkpointing/types.d.ts +98 -0
  19. package/dist/checkpointing/types.d.ts.map +1 -0
  20. package/dist/checkpointing/types.js +7 -0
  21. package/dist/checkpointing/types.js.map +1 -0
  22. package/dist/cli/components/App.d.ts.map +1 -1
  23. package/dist/cli/components/App.js +193 -7
  24. package/dist/cli/components/App.js.map +1 -1
  25. package/dist/cli/components/CommandSuggestions.d.ts.map +1 -1
  26. package/dist/cli/components/CommandSuggestions.js +5 -0
  27. package/dist/cli/components/CommandSuggestions.js.map +1 -1
  28. package/dist/cli/components/Messages.d.ts +7 -1
  29. package/dist/cli/components/Messages.d.ts.map +1 -1
  30. package/dist/cli/components/Messages.js +28 -2
  31. package/dist/cli/components/Messages.js.map +1 -1
  32. package/dist/cli/components/ModeIndicator.d.ts +42 -0
  33. package/dist/cli/components/ModeIndicator.d.ts.map +1 -0
  34. package/dist/cli/components/ModeIndicator.js +52 -0
  35. package/dist/cli/components/ModeIndicator.js.map +1 -0
  36. package/dist/cli/components/PlanApproval.d.ts +36 -0
  37. package/dist/cli/components/PlanApproval.d.ts.map +1 -0
  38. package/dist/cli/components/PlanApproval.js +154 -0
  39. package/dist/cli/components/PlanApproval.js.map +1 -0
  40. package/dist/cli/components/QuestionPrompt.d.ts +23 -0
  41. package/dist/cli/components/QuestionPrompt.d.ts.map +1 -0
  42. package/dist/cli/components/QuestionPrompt.js +231 -0
  43. package/dist/cli/components/QuestionPrompt.js.map +1 -0
  44. package/dist/cli/components/index.d.ts +1 -0
  45. package/dist/cli/components/index.d.ts.map +1 -1
  46. package/dist/cli/components/index.js +1 -0
  47. package/dist/cli/components/index.js.map +1 -1
  48. package/dist/cli/components/theme.d.ts +9 -0
  49. package/dist/cli/components/theme.d.ts.map +1 -1
  50. package/dist/cli/components/theme.js +14 -1
  51. package/dist/cli/components/theme.js.map +1 -1
  52. package/dist/index.d.ts +1 -0
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +2 -0
  55. package/dist/index.js.map +1 -1
  56. package/dist/permissions/types.d.ts.map +1 -1
  57. package/dist/permissions/types.js +2 -0
  58. package/dist/permissions/types.js.map +1 -1
  59. package/dist/planning/index.d.ts +13 -0
  60. package/dist/planning/index.d.ts.map +1 -0
  61. package/dist/planning/index.js +15 -0
  62. package/dist/planning/index.js.map +1 -0
  63. package/dist/planning/plan-file.d.ts +59 -0
  64. package/dist/planning/plan-file.d.ts.map +1 -0
  65. package/dist/planning/plan-file.js +278 -0
  66. package/dist/planning/plan-file.js.map +1 -0
  67. package/dist/planning/state.d.ts +127 -0
  68. package/dist/planning/state.d.ts.map +1 -0
  69. package/dist/planning/state.js +261 -0
  70. package/dist/planning/state.js.map +1 -0
  71. package/dist/planning/tools/enter-plan-mode.d.ts +25 -0
  72. package/dist/planning/tools/enter-plan-mode.d.ts.map +1 -0
  73. package/dist/planning/tools/enter-plan-mode.js +98 -0
  74. package/dist/planning/tools/enter-plan-mode.js.map +1 -0
  75. package/dist/planning/tools/exit-plan-mode.d.ts +24 -0
  76. package/dist/planning/tools/exit-plan-mode.d.ts.map +1 -0
  77. package/dist/planning/tools/exit-plan-mode.js +149 -0
  78. package/dist/planning/tools/exit-plan-mode.js.map +1 -0
  79. package/dist/planning/types.d.ts +100 -0
  80. package/dist/planning/types.d.ts.map +1 -0
  81. package/dist/planning/types.js +28 -0
  82. package/dist/planning/types.js.map +1 -0
  83. package/dist/pricing/calculator.d.ts +21 -0
  84. package/dist/pricing/calculator.d.ts.map +1 -0
  85. package/dist/pricing/calculator.js +59 -0
  86. package/dist/pricing/calculator.js.map +1 -0
  87. package/dist/pricing/index.d.ts +7 -0
  88. package/dist/pricing/index.d.ts.map +1 -0
  89. package/dist/pricing/index.js +7 -0
  90. package/dist/pricing/index.js.map +1 -0
  91. package/dist/pricing/models.d.ts +20 -0
  92. package/dist/pricing/models.d.ts.map +1 -0
  93. package/dist/pricing/models.js +322 -0
  94. package/dist/pricing/models.js.map +1 -0
  95. package/dist/pricing/types.d.ts +30 -0
  96. package/dist/pricing/types.d.ts.map +1 -0
  97. package/dist/pricing/types.js +5 -0
  98. package/dist/pricing/types.js.map +1 -0
  99. package/dist/providers/anthropic.d.ts.map +1 -1
  100. package/dist/providers/anthropic.js +17 -10
  101. package/dist/providers/anthropic.js.map +1 -1
  102. package/dist/providers/gemini.d.ts.map +1 -1
  103. package/dist/providers/gemini.js +21 -14
  104. package/dist/providers/gemini.js.map +1 -1
  105. package/dist/providers/openai.d.ts.map +1 -1
  106. package/dist/providers/openai.js +12 -8
  107. package/dist/providers/openai.js.map +1 -1
  108. package/dist/providers/types.d.ts +2 -0
  109. package/dist/providers/types.d.ts.map +1 -1
  110. package/dist/providers/vertex-ai.d.ts.map +1 -1
  111. package/dist/providers/vertex-ai.js +17 -10
  112. package/dist/providers/vertex-ai.js.map +1 -1
  113. package/dist/session/manager.d.ts +4 -0
  114. package/dist/session/manager.d.ts.map +1 -1
  115. package/dist/session/manager.js +8 -0
  116. package/dist/session/manager.js.map +1 -1
  117. package/dist/tools/builtin/ask-user.d.ts +64 -0
  118. package/dist/tools/builtin/ask-user.d.ts.map +1 -0
  119. package/dist/tools/builtin/ask-user.js +148 -0
  120. package/dist/tools/builtin/ask-user.js.map +1 -0
  121. package/dist/tools/index.d.ts +19 -1
  122. package/dist/tools/index.d.ts.map +1 -1
  123. package/dist/tools/index.js +11 -0
  124. package/dist/tools/index.js.map +1 -1
  125. package/dist/tools/registry.d.ts +13 -0
  126. package/dist/tools/registry.d.ts.map +1 -1
  127. package/dist/tools/registry.js +79 -2
  128. package/dist/tools/registry.js.map +1 -1
  129. package/dist/tools/types.d.ts +17 -0
  130. package/dist/tools/types.d.ts.map +1 -1
  131. package/dist/tools/types.js.map +1 -1
  132. package/docs/cost-tracking-comparison.md +904 -0
  133. package/docs/operating-modes.md +96 -0
  134. package/docs/proposals/0012-ask-user-question.md +66 -1
  135. package/docs/proposals/0025-cost-tracking.md +60 -2
  136. package/docs/proposals/README.md +2 -2
  137. package/examples/test-ask-user.ts +167 -0
  138. package/examples/test-checkpointing.ts +121 -0
  139. package/examples/test-cost-tracking.ts +77 -0
  140. package/examples/test-interrupt-cleanup.ts +94 -0
  141. package/package.json +1 -1
  142. package/src/agent/agent.ts +130 -4
  143. package/src/agent/index.ts +1 -0
  144. package/src/agent/types.ts +19 -1
  145. package/src/checkpointing/checkpoint-manager.ts +327 -0
  146. package/src/checkpointing/index.ts +45 -0
  147. package/src/checkpointing/types.ts +104 -0
  148. package/src/cli/components/App.tsx +259 -8
  149. package/src/cli/components/CommandSuggestions.tsx +5 -0
  150. package/src/cli/components/Messages.tsx +66 -4
  151. package/src/cli/components/ModeIndicator.tsx +174 -0
  152. package/src/cli/components/PlanApproval.tsx +327 -0
  153. package/src/cli/components/QuestionPrompt.tsx +462 -0
  154. package/src/cli/components/index.ts +1 -0
  155. package/src/cli/components/theme.ts +14 -1
  156. package/src/index.ts +15 -0
  157. package/src/permissions/types.ts +2 -0
  158. package/src/planning/index.ts +53 -0
  159. package/src/planning/plan-file.ts +326 -0
  160. package/src/planning/state.ts +305 -0
  161. package/src/planning/tools/enter-plan-mode.ts +111 -0
  162. package/src/planning/tools/exit-plan-mode.ts +170 -0
  163. package/src/planning/types.ts +150 -0
  164. package/src/pricing/calculator.ts +71 -0
  165. package/src/pricing/index.ts +7 -0
  166. package/src/pricing/models.ts +334 -0
  167. package/src/pricing/types.ts +32 -0
  168. package/src/prompts/system/base.txt +42 -0
  169. package/src/prompts/tools/ask-user.txt +110 -0
  170. package/src/providers/anthropic.ts +21 -10
  171. package/src/providers/gemini.ts +25 -14
  172. package/src/providers/openai.ts +17 -8
  173. package/src/providers/types.ts +3 -0
  174. package/src/providers/vertex-ai.ts +21 -10
  175. package/src/session/manager.ts +9 -0
  176. package/src/tools/builtin/ask-user.ts +185 -0
  177. package/src/tools/index.ts +23 -0
  178. package/src/tools/registry.ts +95 -2
  179. package/src/tools/types.ts +18 -0
  180. package/.gencode/settings.local.json +0 -7
@@ -0,0 +1,111 @@
1
+ /**
2
+ * EnterPlanMode Tool
3
+ *
4
+ * Transitions the agent into plan mode for designing implementation
5
+ * approaches before writing code. In plan mode, only read-only tools
6
+ * are available.
7
+ */
8
+
9
+ import { z } from 'zod';
10
+ import type { Tool, ToolResult, ToolContext } from '../../tools/types.js';
11
+ import { getPlanModeManager } from '../state.js';
12
+ import { createPlanFile, getDisplayPath } from '../plan-file.js';
13
+ import { PLAN_MODE_ALLOWED_TOOLS, PLAN_MODE_BLOCKED_TOOLS } from '../types.js';
14
+
15
+ // ============================================================================
16
+ // Tool Definition
17
+ // ============================================================================
18
+
19
+ const EnterPlanModeInputSchema = z.object({});
20
+
21
+ export type EnterPlanModeInput = z.infer<typeof EnterPlanModeInputSchema>;
22
+
23
+ /**
24
+ * EnterPlanMode Tool
25
+ *
26
+ * Use this tool when you need to plan an implementation before writing code.
27
+ * This is recommended for:
28
+ * - New feature implementations
29
+ * - Tasks with multiple valid approaches
30
+ * - Architectural decisions
31
+ * - Multi-file changes
32
+ * - Unclear requirements
33
+ */
34
+ export const enterPlanModeTool: Tool<EnterPlanModeInput> = {
35
+ name: 'EnterPlanMode',
36
+
37
+ description: `Transition into plan mode to design an implementation approach before writing code.
38
+
39
+ Use this tool when:
40
+ - Implementing new features that require design decisions
41
+ - Tasks with multiple valid approaches
42
+ - Changes that affect existing behavior or structure
43
+ - Architectural decisions between patterns or technologies
44
+ - Multi-file changes (more than 2-3 files)
45
+ - Unclear requirements that need exploration
46
+
47
+ In plan mode:
48
+ - Only read-only tools are available (Read, Glob, Grep, WebFetch, WebSearch, TodoWrite, AskUserQuestion)
49
+ - Write, Edit, and Bash tools are blocked
50
+ - You can explore the codebase and design an approach
51
+ - Use ExitPlanMode when ready to request user approval
52
+
53
+ This tool REQUIRES user approval before entering plan mode.`,
54
+
55
+ parameters: EnterPlanModeInputSchema,
56
+
57
+ async execute(_input: EnterPlanModeInput, context: ToolContext): Promise<ToolResult> {
58
+ const manager = getPlanModeManager();
59
+
60
+ // Check if already in plan mode
61
+ if (manager.isActive()) {
62
+ return {
63
+ success: false,
64
+ output: '',
65
+ error: 'Already in plan mode. Use ExitPlanMode to exit first.',
66
+ };
67
+ }
68
+
69
+ try {
70
+ // Create plan file
71
+ const planFile = await createPlanFile(context.cwd);
72
+ const displayPath = getDisplayPath(planFile.path, context.cwd);
73
+
74
+ // Enter plan mode
75
+ manager.enter(planFile.path);
76
+
77
+ // Build response
78
+ const output = `
79
+ Entered PLAN mode.
80
+
81
+ Plan file: ${displayPath}
82
+
83
+ In plan mode, you have access to read-only tools for exploration:
84
+ ${PLAN_MODE_ALLOWED_TOOLS.map((t) => ` - ${t}`).join('\n')}
85
+
86
+ Blocked tools (write/execute operations):
87
+ ${PLAN_MODE_BLOCKED_TOOLS.map((t) => ` - ${t}`).join('\n')}
88
+
89
+ Instructions:
90
+ 1. Explore the codebase using Read, Glob, Grep tools
91
+ 2. Research if needed using WebFetch, WebSearch
92
+ 3. Design your implementation approach
93
+ 4. Write your plan to the plan file using Write (plan file only)
94
+ 5. Call ExitPlanMode when ready for user approval
95
+
96
+ Use Shift+Tab to toggle between Plan and Build modes.
97
+ `.trim();
98
+
99
+ return {
100
+ success: true,
101
+ output,
102
+ };
103
+ } catch (error) {
104
+ return {
105
+ success: false,
106
+ output: '',
107
+ error: `Failed to enter plan mode: ${error instanceof Error ? error.message : String(error)}`,
108
+ };
109
+ }
110
+ },
111
+ };
@@ -0,0 +1,170 @@
1
+ /**
2
+ * ExitPlanMode Tool
3
+ *
4
+ * Exits plan mode and requests user approval for the implementation plan.
5
+ * Supports pre-approving permissions for bash commands needed during execution.
6
+ */
7
+
8
+ import { z } from 'zod';
9
+ import type { Tool, ToolResult, ToolContext } from '../../tools/types.js';
10
+ import { getPlanModeManager } from '../state.js';
11
+ import { readPlanFile, parseFilesToChange, parsePreApprovedPermissions, getDisplayPath } from '../plan-file.js';
12
+ import type { AllowedPrompt } from '../types.js';
13
+
14
+ // ============================================================================
15
+ // Tool Definition
16
+ // ============================================================================
17
+
18
+ const AllowedPromptSchema = z.object({
19
+ tool: z.literal('Bash').describe('The tool this permission applies to'),
20
+ prompt: z.string().describe('Semantic description of the action, e.g., "run tests", "install dependencies"'),
21
+ });
22
+
23
+ const ExitPlanModeInputSchema = z.object({
24
+ allowedPrompts: z
25
+ .array(AllowedPromptSchema)
26
+ .optional()
27
+ .describe('Prompt-based permissions needed to implement the plan'),
28
+ });
29
+
30
+ export type ExitPlanModeInput = z.infer<typeof ExitPlanModeInputSchema>;
31
+
32
+ /**
33
+ * ExitPlanMode Tool
34
+ *
35
+ * Call this when you have finished writing your plan and are ready
36
+ * for user approval. The plan file should already be written.
37
+ */
38
+ export const exitPlanModeTool: Tool<ExitPlanModeInput> = {
39
+ name: 'ExitPlanMode',
40
+
41
+ description: `Exit plan mode and request user approval for the implementation plan.
42
+
43
+ ## How This Tool Works
44
+ - You should have already written your plan to the plan file
45
+ - This tool reads the plan from the file you wrote
46
+ - The user will see the plan contents and approve/modify/cancel
47
+
48
+ ## Requesting Permissions (allowedPrompts)
49
+ Request prompt-based permissions for bash commands your plan will need:
50
+
51
+ \`\`\`json
52
+ {
53
+ "allowedPrompts": [
54
+ { "tool": "Bash", "prompt": "run tests" },
55
+ { "tool": "Bash", "prompt": "install dependencies" },
56
+ { "tool": "Bash", "prompt": "build the project" }
57
+ ]
58
+ }
59
+ \`\`\`
60
+
61
+ Guidelines for prompts:
62
+ - Use semantic descriptions that capture the action's purpose
63
+ - "run tests" matches: npm test, pytest, go test, etc.
64
+ - "install dependencies" matches: npm install, pip install, etc.
65
+ - Keep descriptions concise but descriptive
66
+ - Only request permissions you actually need
67
+ - Scope permissions narrowly
68
+
69
+ ## When to Use This Tool
70
+ Only use this tool when you have finished planning and are ready for approval.
71
+ Do NOT use this tool for research tasks - only for implementation planning.`,
72
+
73
+ parameters: ExitPlanModeInputSchema,
74
+
75
+ async execute(input: ExitPlanModeInput, context: ToolContext): Promise<ToolResult> {
76
+ const manager = getPlanModeManager();
77
+
78
+ // Check if in plan mode
79
+ if (!manager.isActive()) {
80
+ return {
81
+ success: false,
82
+ output: '',
83
+ error: 'Not in plan mode. Use EnterPlanMode first.',
84
+ };
85
+ }
86
+
87
+ const planFilePath = manager.getPlanFilePath();
88
+ if (!planFilePath) {
89
+ return {
90
+ success: false,
91
+ output: '',
92
+ error: 'No plan file found. This should not happen.',
93
+ };
94
+ }
95
+
96
+ try {
97
+ // Read plan file
98
+ const planFile = await readPlanFile(planFilePath);
99
+ if (!planFile) {
100
+ return {
101
+ success: false,
102
+ output: '',
103
+ error: `Could not read plan file: ${planFilePath}`,
104
+ };
105
+ }
106
+
107
+ // Parse plan content
108
+ const filesToChange = parseFilesToChange(planFile.content);
109
+ const planPermissions = parsePreApprovedPermissions(planFile.content);
110
+
111
+ // Combine with input permissions
112
+ const requestedPermissions: AllowedPrompt[] = [
113
+ ...planPermissions,
114
+ ...(input.allowedPrompts || []),
115
+ ];
116
+
117
+ // Store permissions for approval UI
118
+ manager.setRequestedPermissions(requestedPermissions);
119
+ manager.setPhase('approval');
120
+
121
+ // Build response for the LLM
122
+ const displayPath = getDisplayPath(planFilePath, context.cwd);
123
+ let output = `
124
+ Plan ready for approval.
125
+
126
+ Plan file: ${displayPath}
127
+
128
+ `;
129
+
130
+ // Summary of files to change
131
+ if (filesToChange.length > 0) {
132
+ output += 'Files to change:\n';
133
+ for (const file of filesToChange) {
134
+ const icon = file.action === 'create' ? '+' : file.action === 'modify' ? '~' : '-';
135
+ output += ` ${icon} ${file.path} (${file.action})\n`;
136
+ }
137
+ output += '\n';
138
+ }
139
+
140
+ // Requested permissions
141
+ if (requestedPermissions.length > 0) {
142
+ output += 'Requested permissions:\n';
143
+ for (const perm of requestedPermissions) {
144
+ output += ` - ${perm.tool}(prompt: ${perm.prompt})\n`;
145
+ }
146
+ output += '\n';
147
+ }
148
+
149
+ output += `
150
+ The user will now be prompted to:
151
+ 1. Approve - Accept plan and proceed with execution
152
+ 2. Modify - Go back and modify the plan
153
+ 3. Cancel - Exit plan mode without executing
154
+
155
+ Waiting for user decision...
156
+ `.trim();
157
+
158
+ return {
159
+ success: true,
160
+ output,
161
+ };
162
+ } catch (error) {
163
+ return {
164
+ success: false,
165
+ output: '',
166
+ error: `Failed to exit plan mode: ${error instanceof Error ? error.message : String(error)}`,
167
+ };
168
+ }
169
+ },
170
+ };
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Plan Mode Type Definitions
3
+ *
4
+ * Types for Plan Mode - a read-only exploration mode that allows
5
+ * the LLM to plan implementations before executing changes.
6
+ */
7
+
8
+ // ============================================================================
9
+ // Plan Mode State Types
10
+ // ============================================================================
11
+
12
+ /**
13
+ * Plan mode phases following Claude Code's workflow
14
+ */
15
+ export type PlanPhase =
16
+ | 'understanding' // Initial exploration
17
+ | 'design' // Planning approach
18
+ | 'review' // Clarifying with user
19
+ | 'final' // Writing plan file
20
+ | 'approval'; // Waiting for user approval
21
+
22
+ /**
23
+ * User approval options for plan mode
24
+ */
25
+ export type PlanApprovalOption =
26
+ | 'approve' // Accept plan and execute with auto-accept edits
27
+ | 'approve_clear' // Accept plan, clear context, auto-accept edits
28
+ | 'approve_manual' // Accept plan but manually approve each edit
29
+ | 'modify' // Go back to modify the plan
30
+ | 'cancel'; // Cancel plan mode entirely
31
+
32
+ /**
33
+ * Pre-approved permission request (Claude Code ExitPlanMode style)
34
+ */
35
+ export interface AllowedPrompt {
36
+ tool: 'Bash';
37
+ prompt: string; // Semantic description, e.g., "run tests", "install dependencies"
38
+ }
39
+
40
+ /**
41
+ * Plan mode state
42
+ */
43
+ export interface PlanModeState {
44
+ /** Whether plan mode is currently active */
45
+ active: boolean;
46
+
47
+ /** Current phase of planning */
48
+ phase: PlanPhase;
49
+
50
+ /** Path to the plan file */
51
+ planFilePath: string | null;
52
+
53
+ /** User's original request that triggered plan mode */
54
+ originalRequest: string | null;
55
+
56
+ /** Requested permissions for execution phase */
57
+ requestedPermissions: AllowedPrompt[];
58
+
59
+ /** Timestamp when plan mode was entered */
60
+ enteredAt: Date | null;
61
+ }
62
+
63
+ /**
64
+ * Plan file structure
65
+ */
66
+ export interface PlanFile {
67
+ /** Plan file path */
68
+ path: string;
69
+
70
+ /** Plan content in markdown */
71
+ content: string;
72
+
73
+ /** Creation timestamp */
74
+ createdAt: Date;
75
+
76
+ /** Last update timestamp */
77
+ updatedAt: Date;
78
+ }
79
+
80
+ // ============================================================================
81
+ // Tool Filtering Types
82
+ // ============================================================================
83
+
84
+ /**
85
+ * Tools allowed in plan mode (read-only + planning tools)
86
+ */
87
+ export const PLAN_MODE_ALLOWED_TOOLS = [
88
+ 'Read',
89
+ 'Glob',
90
+ 'Grep',
91
+ 'WebFetch',
92
+ 'WebSearch',
93
+ 'TodoWrite',
94
+ 'AskUserQuestion',
95
+ 'EnterPlanMode', // Can re-enter if needed
96
+ 'ExitPlanMode', // To exit plan mode
97
+ ] as const;
98
+
99
+ /**
100
+ * Tools blocked in plan mode (write/execute operations)
101
+ */
102
+ export const PLAN_MODE_BLOCKED_TOOLS = ['Write', 'Edit', 'Bash'] as const;
103
+
104
+ export type PlanModeAllowedTool = (typeof PLAN_MODE_ALLOWED_TOOLS)[number];
105
+ export type PlanModeBlockedTool = (typeof PLAN_MODE_BLOCKED_TOOLS)[number];
106
+
107
+ // ============================================================================
108
+ // UI Types
109
+ // ============================================================================
110
+
111
+ /**
112
+ * Operating mode (cycle with Shift+Tab: normal → plan → accept → normal)
113
+ * - normal: Default mode, edits require confirmation
114
+ * - plan: Read-only exploration mode, edits blocked
115
+ * - accept: Auto-accept mode, edits approved without confirmation
116
+ */
117
+ export type ModeType = 'normal' | 'plan' | 'accept';
118
+
119
+ /**
120
+ * Plan approval UI state
121
+ */
122
+ export interface PlanApprovalState {
123
+ /** Plan content for display */
124
+ planContent: string;
125
+
126
+ /** Summary of files to change */
127
+ filesToChange: Array<{
128
+ path: string;
129
+ action: 'create' | 'modify' | 'delete';
130
+ }>;
131
+
132
+ /** Requested permissions */
133
+ requestedPermissions: AllowedPrompt[];
134
+
135
+ /** Callback when user makes decision */
136
+ onDecision: (option: PlanApprovalOption) => void;
137
+ }
138
+
139
+ // ============================================================================
140
+ // Event Types
141
+ // ============================================================================
142
+
143
+ /**
144
+ * Plan mode events for UI updates
145
+ */
146
+ export type PlanModeEvent =
147
+ | { type: 'enter'; planFilePath: string }
148
+ | { type: 'phase_change'; phase: PlanPhase }
149
+ | { type: 'exit'; approved: boolean }
150
+ | { type: 'toggle' }; // Shift+Tab toggle
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Cost calculation utilities
3
+ */
4
+
5
+ import { getModelPricing } from './models.js';
6
+ import { CostEstimate, TokenUsage } from './types.js';
7
+
8
+ /**
9
+ * Calculate cost from token usage
10
+ */
11
+ export function calculateCost(
12
+ provider: string,
13
+ model: string,
14
+ tokens: TokenUsage
15
+ ): CostEstimate {
16
+ const pricing = getModelPricing(provider, model);
17
+
18
+ // If no pricing found, return zero cost
19
+ if (!pricing) {
20
+ return {
21
+ inputCost: 0,
22
+ outputCost: 0,
23
+ totalCost: 0,
24
+ currency: 'USD',
25
+ };
26
+ }
27
+
28
+ // Calculate cost per token type
29
+ const inputCost = (tokens.inputTokens / 1_000_000) * pricing.inputPer1M;
30
+ const outputCost = (tokens.outputTokens / 1_000_000) * pricing.outputPer1M;
31
+
32
+ return {
33
+ inputCost,
34
+ outputCost,
35
+ totalCost: inputCost + outputCost,
36
+ currency: 'USD',
37
+ };
38
+ }
39
+
40
+ /**
41
+ * Format cost for display
42
+ */
43
+ export function formatCost(cost: number): string {
44
+ if (cost === 0) {
45
+ return '$0.00';
46
+ }
47
+ if (cost < 0.01) {
48
+ return '<$0.01';
49
+ }
50
+ return `$${cost.toFixed(2)}`;
51
+ }
52
+
53
+ /**
54
+ * Format token count for display
55
+ */
56
+ export function formatTokens(count: number): string {
57
+ if (count >= 1_000_000) {
58
+ return `${(count / 1_000_000).toFixed(1)}M`;
59
+ }
60
+ if (count >= 1_000) {
61
+ return `${(count / 1_000).toFixed(1)}K`;
62
+ }
63
+ return count.toString();
64
+ }
65
+
66
+ /**
67
+ * Format cost estimate for display
68
+ */
69
+ export function formatCostEstimate(estimate: CostEstimate): string {
70
+ return formatCost(estimate.totalCost);
71
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Pricing and cost tracking module
3
+ */
4
+
5
+ export * from './types.js';
6
+ export * from './models.js';
7
+ export * from './calculator.js';