popeye-cli 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/.env.example +25 -0
- package/.prettierrc +8 -0
- package/README.md +320 -0
- package/dist/adapters/claude.d.ts +82 -0
- package/dist/adapters/claude.d.ts.map +1 -0
- package/dist/adapters/claude.js +230 -0
- package/dist/adapters/claude.js.map +1 -0
- package/dist/adapters/openai.d.ts +48 -0
- package/dist/adapters/openai.d.ts.map +1 -0
- package/dist/adapters/openai.js +257 -0
- package/dist/adapters/openai.js.map +1 -0
- package/dist/auth/claude.d.ts +44 -0
- package/dist/auth/claude.d.ts.map +1 -0
- package/dist/auth/claude.js +139 -0
- package/dist/auth/claude.js.map +1 -0
- package/dist/auth/index.d.ts +61 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +141 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/keychain.d.ts +66 -0
- package/dist/auth/keychain.d.ts.map +1 -0
- package/dist/auth/keychain.js +125 -0
- package/dist/auth/keychain.js.map +1 -0
- package/dist/auth/openai-entry.d.ts +9 -0
- package/dist/auth/openai-entry.d.ts.map +1 -0
- package/dist/auth/openai-entry.js +410 -0
- package/dist/auth/openai-entry.js.map +1 -0
- package/dist/auth/openai.d.ts +71 -0
- package/dist/auth/openai.d.ts.map +1 -0
- package/dist/auth/openai.js +212 -0
- package/dist/auth/openai.js.map +1 -0
- package/dist/auth/server.d.ts +32 -0
- package/dist/auth/server.d.ts.map +1 -0
- package/dist/auth/server.js +213 -0
- package/dist/auth/server.js.map +1 -0
- package/dist/cli/commands/auth.d.ts +10 -0
- package/dist/cli/commands/auth.d.ts.map +1 -0
- package/dist/cli/commands/auth.js +162 -0
- package/dist/cli/commands/auth.js.map +1 -0
- package/dist/cli/commands/config.d.ts +10 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +215 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/create.d.ts +10 -0
- package/dist/cli/commands/create.d.ts.map +1 -0
- package/dist/cli/commands/create.js +240 -0
- package/dist/cli/commands/create.js.map +1 -0
- package/dist/cli/commands/index.d.ts +10 -0
- package/dist/cli/commands/index.d.ts.map +1 -0
- package/dist/cli/commands/index.js +10 -0
- package/dist/cli/commands/index.js.map +1 -0
- package/dist/cli/commands/resume.d.ts +18 -0
- package/dist/cli/commands/resume.d.ts.map +1 -0
- package/dist/cli/commands/resume.js +241 -0
- package/dist/cli/commands/resume.js.map +1 -0
- package/dist/cli/commands/status.d.ts +18 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +154 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/index.d.ts +17 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +71 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/interactive.d.ts +9 -0
- package/dist/cli/interactive.d.ts.map +1 -0
- package/dist/cli/interactive.js +330 -0
- package/dist/cli/interactive.js.map +1 -0
- package/dist/cli/output.d.ts +182 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +355 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/config/defaults.d.ts +57 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +103 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/index.d.ts +138 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +244 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/schema.d.ts +220 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +141 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/generators/index.d.ts +101 -0
- package/dist/generators/index.d.ts.map +1 -0
- package/dist/generators/index.js +200 -0
- package/dist/generators/index.js.map +1 -0
- package/dist/generators/python.d.ts +48 -0
- package/dist/generators/python.d.ts.map +1 -0
- package/dist/generators/python.js +262 -0
- package/dist/generators/python.js.map +1 -0
- package/dist/generators/templates/index.d.ts +6 -0
- package/dist/generators/templates/index.d.ts.map +1 -0
- package/dist/generators/templates/index.js +6 -0
- package/dist/generators/templates/index.js.map +1 -0
- package/dist/generators/templates/python.d.ts +53 -0
- package/dist/generators/templates/python.d.ts.map +1 -0
- package/dist/generators/templates/python.js +454 -0
- package/dist/generators/templates/python.js.map +1 -0
- package/dist/generators/templates/typescript.d.ts +53 -0
- package/dist/generators/templates/typescript.d.ts.map +1 -0
- package/dist/generators/templates/typescript.js +394 -0
- package/dist/generators/templates/typescript.js.map +1 -0
- package/dist/generators/typescript.d.ts +64 -0
- package/dist/generators/typescript.d.ts.map +1 -0
- package/dist/generators/typescript.js +271 -0
- package/dist/generators/typescript.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/state/index.d.ts +168 -0
- package/dist/state/index.d.ts.map +1 -0
- package/dist/state/index.js +338 -0
- package/dist/state/index.js.map +1 -0
- package/dist/state/persistence.d.ts +91 -0
- package/dist/state/persistence.d.ts.map +1 -0
- package/dist/state/persistence.js +201 -0
- package/dist/state/persistence.js.map +1 -0
- package/dist/types/cli.d.ts +132 -0
- package/dist/types/cli.d.ts.map +1 -0
- package/dist/types/cli.js +17 -0
- package/dist/types/cli.js.map +1 -0
- package/dist/types/consensus.d.ts +111 -0
- package/dist/types/consensus.d.ts.map +1 -0
- package/dist/types/consensus.js +29 -0
- package/dist/types/consensus.js.map +1 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +13 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/project.d.ts +73 -0
- package/dist/types/project.d.ts.map +1 -0
- package/dist/types/project.js +55 -0
- package/dist/types/project.js.map +1 -0
- package/dist/types/workflow.d.ts +236 -0
- package/dist/types/workflow.d.ts.map +1 -0
- package/dist/types/workflow.js +74 -0
- package/dist/types/workflow.js.map +1 -0
- package/dist/workflow/consensus.d.ts +89 -0
- package/dist/workflow/consensus.d.ts.map +1 -0
- package/dist/workflow/consensus.js +220 -0
- package/dist/workflow/consensus.js.map +1 -0
- package/dist/workflow/execution-mode.d.ts +82 -0
- package/dist/workflow/execution-mode.d.ts.map +1 -0
- package/dist/workflow/execution-mode.js +346 -0
- package/dist/workflow/execution-mode.js.map +1 -0
- package/dist/workflow/index.d.ts +110 -0
- package/dist/workflow/index.d.ts.map +1 -0
- package/dist/workflow/index.js +283 -0
- package/dist/workflow/index.js.map +1 -0
- package/dist/workflow/plan-mode.d.ts +83 -0
- package/dist/workflow/plan-mode.d.ts.map +1 -0
- package/dist/workflow/plan-mode.js +241 -0
- package/dist/workflow/plan-mode.js.map +1 -0
- package/dist/workflow/test-runner.d.ts +87 -0
- package/dist/workflow/test-runner.d.ts.map +1 -0
- package/dist/workflow/test-runner.js +273 -0
- package/dist/workflow/test-runner.js.map +1 -0
- package/eslint.config.js +25 -0
- package/package.json +66 -0
- package/src/adapters/claude.ts +298 -0
- package/src/adapters/openai.ts +300 -0
- package/src/auth/claude.ts +166 -0
- package/src/auth/index.ts +171 -0
- package/src/auth/keychain.ts +138 -0
- package/src/auth/openai-entry.ts +410 -0
- package/src/auth/openai.ts +260 -0
- package/src/auth/server.ts +252 -0
- package/src/cli/commands/auth.ts +194 -0
- package/src/cli/commands/config.ts +241 -0
- package/src/cli/commands/create.ts +308 -0
- package/src/cli/commands/index.ts +10 -0
- package/src/cli/commands/resume.ts +304 -0
- package/src/cli/commands/status.ts +189 -0
- package/src/cli/index.ts +90 -0
- package/src/cli/interactive.ts +418 -0
- package/src/cli/output.ts +410 -0
- package/src/config/defaults.ts +114 -0
- package/src/config/index.ts +315 -0
- package/src/config/schema.ts +164 -0
- package/src/generators/index.ts +251 -0
- package/src/generators/python.ts +318 -0
- package/src/generators/templates/index.ts +6 -0
- package/src/generators/templates/python.ts +465 -0
- package/src/generators/templates/typescript.ts +417 -0
- package/src/generators/typescript.ts +340 -0
- package/src/index.ts +13 -0
- package/src/state/index.ts +454 -0
- package/src/state/persistence.ts +230 -0
- package/src/types/cli.ts +146 -0
- package/src/types/consensus.ts +116 -0
- package/src/types/index.ts +64 -0
- package/src/types/project.ts +85 -0
- package/src/types/workflow.ts +149 -0
- package/src/workflow/consensus.ts +299 -0
- package/src/workflow/execution-mode.ts +517 -0
- package/src/workflow/index.ts +396 -0
- package/src/workflow/plan-mode.ts +356 -0
- package/src/workflow/test-runner.ts +345 -0
- package/tests/adapters/openai.test.ts +145 -0
- package/tests/config/config.test.ts +208 -0
- package/tests/generators/generators.test.ts +185 -0
- package/tests/types/consensus.test.ts +152 -0
- package/tests/types/project.test.ts +134 -0
- package/tests/workflow/consensus.test.ts +221 -0
- package/tests/workflow/test-runner.test.ts +214 -0
- package/tsconfig.json +25 -0
- package/vitest.config.ts +22 -0
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI output utilities
|
|
3
|
+
* Handles formatted output, spinners, and progress display
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import ora, { type Ora } from 'ora';
|
|
8
|
+
import type { ProjectState, Milestone, Task } from '../types/workflow.js';
|
|
9
|
+
import type { ConsensusResult } from '../types/consensus.js';
|
|
10
|
+
import type { TestResult } from '../workflow/test-runner.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Output theme colors
|
|
14
|
+
*/
|
|
15
|
+
export const theme = {
|
|
16
|
+
primary: chalk.cyan,
|
|
17
|
+
secondary: chalk.gray,
|
|
18
|
+
success: chalk.green,
|
|
19
|
+
warning: chalk.yellow,
|
|
20
|
+
error: chalk.red,
|
|
21
|
+
info: chalk.blue,
|
|
22
|
+
highlight: chalk.bold.white,
|
|
23
|
+
dim: chalk.dim,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Spinner instance for progress display
|
|
28
|
+
*/
|
|
29
|
+
let spinner: Ora | null = null;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Start a spinner with a message
|
|
33
|
+
*
|
|
34
|
+
* @param message - Initial message
|
|
35
|
+
* @returns Spinner instance
|
|
36
|
+
*/
|
|
37
|
+
export function startSpinner(message: string): Ora {
|
|
38
|
+
if (spinner) {
|
|
39
|
+
spinner.stop();
|
|
40
|
+
}
|
|
41
|
+
spinner = ora({
|
|
42
|
+
text: message,
|
|
43
|
+
spinner: 'dots',
|
|
44
|
+
}).start();
|
|
45
|
+
return spinner;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Update spinner message
|
|
50
|
+
*
|
|
51
|
+
* @param message - New message
|
|
52
|
+
*/
|
|
53
|
+
export function updateSpinner(message: string): void {
|
|
54
|
+
if (spinner) {
|
|
55
|
+
spinner.text = message;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Stop spinner with success
|
|
61
|
+
*
|
|
62
|
+
* @param message - Success message
|
|
63
|
+
*/
|
|
64
|
+
export function succeedSpinner(message?: string): void {
|
|
65
|
+
if (spinner) {
|
|
66
|
+
spinner.succeed(message);
|
|
67
|
+
spinner = null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Stop spinner with failure
|
|
73
|
+
*
|
|
74
|
+
* @param message - Failure message
|
|
75
|
+
*/
|
|
76
|
+
export function failSpinner(message?: string): void {
|
|
77
|
+
if (spinner) {
|
|
78
|
+
spinner.fail(message);
|
|
79
|
+
spinner = null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Stop spinner without status
|
|
85
|
+
*/
|
|
86
|
+
export function stopSpinner(): void {
|
|
87
|
+
if (spinner) {
|
|
88
|
+
spinner.stop();
|
|
89
|
+
spinner = null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Print a header
|
|
95
|
+
*
|
|
96
|
+
* @param title - Header title
|
|
97
|
+
*/
|
|
98
|
+
export function printHeader(title: string): void {
|
|
99
|
+
console.log();
|
|
100
|
+
console.log(theme.primary.bold(`=== ${title} ===`));
|
|
101
|
+
console.log();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Print a section header
|
|
106
|
+
*
|
|
107
|
+
* @param title - Section title
|
|
108
|
+
*/
|
|
109
|
+
export function printSection(title: string): void {
|
|
110
|
+
console.log();
|
|
111
|
+
console.log(theme.highlight(`--- ${title} ---`));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Print a success message
|
|
116
|
+
*
|
|
117
|
+
* @param message - Success message
|
|
118
|
+
*/
|
|
119
|
+
export function printSuccess(message: string): void {
|
|
120
|
+
console.log(theme.success(`[OK] ${message}`));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Print a warning message
|
|
125
|
+
*
|
|
126
|
+
* @param message - Warning message
|
|
127
|
+
*/
|
|
128
|
+
export function printWarning(message: string): void {
|
|
129
|
+
console.log(theme.warning(`[WARN] ${message}`));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Print an error message
|
|
134
|
+
*
|
|
135
|
+
* @param message - Error message
|
|
136
|
+
*/
|
|
137
|
+
export function printError(message: string): void {
|
|
138
|
+
console.log(theme.error(`[ERROR] ${message}`));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Print an info message
|
|
143
|
+
*
|
|
144
|
+
* @param message - Info message
|
|
145
|
+
*/
|
|
146
|
+
export function printInfo(message: string): void {
|
|
147
|
+
console.log(theme.info(`[INFO] ${message}`));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Print a key-value pair
|
|
152
|
+
*
|
|
153
|
+
* @param key - Key
|
|
154
|
+
* @param value - Value
|
|
155
|
+
*/
|
|
156
|
+
export function printKeyValue(key: string, value: string | number | boolean): void {
|
|
157
|
+
console.log(` ${theme.secondary(key + ':')} ${value}`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Print a list item
|
|
162
|
+
*
|
|
163
|
+
* @param item - List item
|
|
164
|
+
* @param indent - Indentation level
|
|
165
|
+
*/
|
|
166
|
+
export function printListItem(item: string, indent: number = 0): void {
|
|
167
|
+
const prefix = ' '.repeat(indent) + '- ';
|
|
168
|
+
console.log(theme.secondary(prefix) + item);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Print project state summary
|
|
173
|
+
*
|
|
174
|
+
* @param state - Project state
|
|
175
|
+
*/
|
|
176
|
+
export function printProjectState(state: ProjectState): void {
|
|
177
|
+
printHeader(`Project: ${state.name}`);
|
|
178
|
+
|
|
179
|
+
printKeyValue('ID', state.id);
|
|
180
|
+
printKeyValue('Language', state.language);
|
|
181
|
+
printKeyValue('Phase', state.phase);
|
|
182
|
+
printKeyValue('Status', state.status);
|
|
183
|
+
printKeyValue('Created', state.createdAt);
|
|
184
|
+
printKeyValue('Updated', state.updatedAt);
|
|
185
|
+
|
|
186
|
+
if (state.error) {
|
|
187
|
+
printSection('Error');
|
|
188
|
+
printError(state.error);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (state.milestones.length > 0) {
|
|
192
|
+
printSection('Milestones');
|
|
193
|
+
for (const milestone of state.milestones) {
|
|
194
|
+
printMilestone(milestone);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Print milestone summary
|
|
201
|
+
*
|
|
202
|
+
* @param milestone - Milestone
|
|
203
|
+
*/
|
|
204
|
+
export function printMilestone(milestone: Milestone): void {
|
|
205
|
+
const statusIcon = getStatusIcon(milestone.status);
|
|
206
|
+
console.log(`\n ${statusIcon} ${theme.highlight(milestone.name)}`);
|
|
207
|
+
|
|
208
|
+
if (milestone.tasks.length > 0) {
|
|
209
|
+
for (const task of milestone.tasks) {
|
|
210
|
+
printTask(task, 2);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Print task summary
|
|
217
|
+
*
|
|
218
|
+
* @param task - Task
|
|
219
|
+
* @param indent - Indentation level
|
|
220
|
+
*/
|
|
221
|
+
export function printTask(task: Task, indent: number = 0): void {
|
|
222
|
+
const statusIcon = getStatusIcon(task.status);
|
|
223
|
+
const prefix = ' '.repeat(indent);
|
|
224
|
+
console.log(`${prefix}${statusIcon} ${task.name}`);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Get status icon
|
|
229
|
+
*
|
|
230
|
+
* @param status - Status
|
|
231
|
+
* @returns Status icon
|
|
232
|
+
*/
|
|
233
|
+
function getStatusIcon(status: string): string {
|
|
234
|
+
switch (status) {
|
|
235
|
+
case 'complete':
|
|
236
|
+
return theme.success('[OK]');
|
|
237
|
+
case 'in-progress':
|
|
238
|
+
return theme.warning('[..]');
|
|
239
|
+
case 'failed':
|
|
240
|
+
return theme.error('[X]');
|
|
241
|
+
default:
|
|
242
|
+
return theme.dim('[ ]');
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Print consensus result
|
|
248
|
+
*
|
|
249
|
+
* @param result - Consensus result
|
|
250
|
+
*/
|
|
251
|
+
export function printConsensusResult(result: ConsensusResult): void {
|
|
252
|
+
const scoreColor = result.score >= 95 ? theme.success :
|
|
253
|
+
result.score >= 80 ? theme.warning : theme.error;
|
|
254
|
+
|
|
255
|
+
printSection('Consensus Review');
|
|
256
|
+
console.log(` Score: ${scoreColor(`${result.score}%`)}`);
|
|
257
|
+
console.log(` Status: ${result.approved ? theme.success('APPROVED') : theme.warning('PENDING')}`);
|
|
258
|
+
|
|
259
|
+
if (result.strengths && result.strengths.length > 0) {
|
|
260
|
+
console.log();
|
|
261
|
+
console.log(theme.success(' Strengths:'));
|
|
262
|
+
for (const strength of result.strengths.slice(0, 3)) {
|
|
263
|
+
printListItem(strength, 2);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (result.concerns && result.concerns.length > 0) {
|
|
268
|
+
console.log();
|
|
269
|
+
console.log(theme.warning(' Concerns:'));
|
|
270
|
+
for (const concern of result.concerns.slice(0, 3)) {
|
|
271
|
+
printListItem(concern, 2);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Print test result
|
|
278
|
+
*
|
|
279
|
+
* @param result - Test result
|
|
280
|
+
*/
|
|
281
|
+
export function printTestResult(result: TestResult): void {
|
|
282
|
+
printSection('Test Results');
|
|
283
|
+
|
|
284
|
+
if (result.error) {
|
|
285
|
+
printError(result.error);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const statusIcon = result.success ? theme.success('[PASS]') : theme.error('[FAIL]');
|
|
290
|
+
console.log(` ${statusIcon} ${result.passed}/${result.total} tests passed`);
|
|
291
|
+
|
|
292
|
+
if (result.failedTests && result.failedTests.length > 0) {
|
|
293
|
+
console.log();
|
|
294
|
+
console.log(theme.error(' Failed tests:'));
|
|
295
|
+
for (const test of result.failedTests.slice(0, 5)) {
|
|
296
|
+
printListItem(test, 2);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Print progress bar
|
|
303
|
+
*
|
|
304
|
+
* @param current - Current value
|
|
305
|
+
* @param total - Total value
|
|
306
|
+
* @param label - Label
|
|
307
|
+
*/
|
|
308
|
+
export function printProgress(current: number, total: number, label?: string): void {
|
|
309
|
+
const percent = total > 0 ? Math.round((current / total) * 100) : 0;
|
|
310
|
+
const barWidth = 30;
|
|
311
|
+
const filled = Math.round((percent / 100) * barWidth);
|
|
312
|
+
const empty = barWidth - filled;
|
|
313
|
+
|
|
314
|
+
const bar = theme.success('#'.repeat(filled)) + theme.dim('-'.repeat(empty));
|
|
315
|
+
const percentStr = `${percent}%`.padStart(4);
|
|
316
|
+
|
|
317
|
+
console.log(` [${bar}] ${percentStr}${label ? ` - ${label}` : ''}`);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Print authentication status
|
|
322
|
+
*
|
|
323
|
+
* @param status - Authentication status
|
|
324
|
+
*/
|
|
325
|
+
export function printAuthStatus(status: {
|
|
326
|
+
claude: { authenticated: boolean; user?: string };
|
|
327
|
+
openai: { authenticated: boolean; keyLastFour?: string };
|
|
328
|
+
}): void {
|
|
329
|
+
printSection('Authentication Status');
|
|
330
|
+
|
|
331
|
+
// Claude status
|
|
332
|
+
const claudeIcon = status.claude.authenticated ? theme.success('[OK]') : theme.error('[X]');
|
|
333
|
+
const claudeInfo = status.claude.user || 'Not authenticated';
|
|
334
|
+
console.log(` ${claudeIcon} Claude CLI: ${claudeInfo}`);
|
|
335
|
+
|
|
336
|
+
// OpenAI status
|
|
337
|
+
const openaiIcon = status.openai.authenticated ? theme.success('[OK]') : theme.error('[X]');
|
|
338
|
+
const openaiInfo = status.openai.keyLastFour
|
|
339
|
+
? `Authenticated (****${status.openai.keyLastFour})`
|
|
340
|
+
: 'Not authenticated';
|
|
341
|
+
console.log(` ${openaiIcon} OpenAI API: ${openaiInfo}`);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Print help for a command
|
|
346
|
+
*
|
|
347
|
+
* @param command - Command name
|
|
348
|
+
* @param description - Command description
|
|
349
|
+
* @param usage - Usage string
|
|
350
|
+
* @param options - Command options
|
|
351
|
+
*/
|
|
352
|
+
export function printHelp(
|
|
353
|
+
command: string,
|
|
354
|
+
description: string,
|
|
355
|
+
usage: string,
|
|
356
|
+
options?: Array<{ flag: string; description: string }>
|
|
357
|
+
): void {
|
|
358
|
+
printHeader(command);
|
|
359
|
+
console.log(description);
|
|
360
|
+
console.log();
|
|
361
|
+
console.log(theme.highlight('Usage:'));
|
|
362
|
+
console.log(` ${usage}`);
|
|
363
|
+
|
|
364
|
+
if (options && options.length > 0) {
|
|
365
|
+
console.log();
|
|
366
|
+
console.log(theme.highlight('Options:'));
|
|
367
|
+
for (const opt of options) {
|
|
368
|
+
console.log(` ${theme.primary(opt.flag.padEnd(20))} ${opt.description}`);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Print a table
|
|
375
|
+
*
|
|
376
|
+
* @param headers - Table headers
|
|
377
|
+
* @param rows - Table rows
|
|
378
|
+
*/
|
|
379
|
+
export function printTable(headers: string[], rows: string[][]): void {
|
|
380
|
+
// Calculate column widths
|
|
381
|
+
const widths = headers.map((h, i) => {
|
|
382
|
+
const maxRow = Math.max(...rows.map((r) => (r[i] || '').length));
|
|
383
|
+
return Math.max(h.length, maxRow);
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
// Print header
|
|
387
|
+
const headerLine = headers.map((h, i) => h.padEnd(widths[i])).join(' ');
|
|
388
|
+
console.log(theme.highlight(headerLine));
|
|
389
|
+
console.log(theme.dim('-'.repeat(headerLine.length)));
|
|
390
|
+
|
|
391
|
+
// Print rows
|
|
392
|
+
for (const row of rows) {
|
|
393
|
+
const rowLine = row.map((cell, i) => (cell || '').padEnd(widths[i])).join(' ');
|
|
394
|
+
console.log(rowLine);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Clear the console
|
|
400
|
+
*/
|
|
401
|
+
export function clearConsole(): void {
|
|
402
|
+
console.clear();
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Print a blank line
|
|
407
|
+
*/
|
|
408
|
+
export function printBlank(): void {
|
|
409
|
+
console.log();
|
|
410
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default configuration values
|
|
3
|
+
* Matches popeye-cli-spec.md section 9.1 exactly
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Config } from './schema.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Default configuration object
|
|
10
|
+
*/
|
|
11
|
+
export const DEFAULT_CONFIG: Config = {
|
|
12
|
+
consensus: {
|
|
13
|
+
threshold: 95,
|
|
14
|
+
max_disagreements: 5,
|
|
15
|
+
escalation_action: 'pause',
|
|
16
|
+
},
|
|
17
|
+
apis: {
|
|
18
|
+
openai: {
|
|
19
|
+
model: 'gpt-4o',
|
|
20
|
+
temperature: 0.3,
|
|
21
|
+
max_tokens: 4096,
|
|
22
|
+
available_models: ['gpt-4o', 'gpt-4o-mini', 'gpt-4-turbo', 'o1-preview', 'o1-mini'],
|
|
23
|
+
},
|
|
24
|
+
claude: {
|
|
25
|
+
model: 'claude-sonnet-4-20250514',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
project: {
|
|
29
|
+
default_language: 'python',
|
|
30
|
+
python: {
|
|
31
|
+
package_manager: 'pip',
|
|
32
|
+
test_framework: 'pytest',
|
|
33
|
+
min_version: '3.10',
|
|
34
|
+
},
|
|
35
|
+
typescript: {
|
|
36
|
+
package_manager: 'npm',
|
|
37
|
+
test_framework: 'jest',
|
|
38
|
+
min_version: '18',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
directories: {
|
|
42
|
+
docs: 'docs',
|
|
43
|
+
tests: 'docs/tests',
|
|
44
|
+
plans: 'docs/plans',
|
|
45
|
+
},
|
|
46
|
+
output: {
|
|
47
|
+
format: 'markdown',
|
|
48
|
+
verbose: false,
|
|
49
|
+
timestamps: true,
|
|
50
|
+
show_consensus_dialog: true,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Configuration file names to search for
|
|
56
|
+
*/
|
|
57
|
+
export const CONFIG_FILE_NAMES = [
|
|
58
|
+
'popeye.config.yaml',
|
|
59
|
+
'popeye.config.yml',
|
|
60
|
+
'.popeyerc.yaml',
|
|
61
|
+
'.popeyerc.yml',
|
|
62
|
+
'.popeyerc',
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Global config directory path
|
|
67
|
+
*/
|
|
68
|
+
export const GLOBAL_CONFIG_DIR = '.popeye';
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* State file name
|
|
72
|
+
*/
|
|
73
|
+
export const STATE_FILE_NAME = 'state.json';
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Config file name in .popeye directory
|
|
77
|
+
*/
|
|
78
|
+
export const CONFIG_FILE_NAME = 'config.yaml';
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Service name for keychain
|
|
82
|
+
*/
|
|
83
|
+
export const SERVICE_NAME = 'popeye-cli';
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Keychain account names
|
|
87
|
+
*/
|
|
88
|
+
export const KEYCHAIN_ACCOUNTS = {
|
|
89
|
+
CLAUDE: 'claude-cli',
|
|
90
|
+
OPENAI: 'openai-api',
|
|
91
|
+
} as const;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Environment variable names
|
|
95
|
+
*/
|
|
96
|
+
export const ENV_VARS = {
|
|
97
|
+
OPENAI_KEY: 'POPEYE_OPENAI_KEY',
|
|
98
|
+
ANTHROPIC_KEY: 'POPEYE_ANTHROPIC_KEY',
|
|
99
|
+
DEFAULT_LANGUAGE: 'POPEYE_DEFAULT_LANGUAGE',
|
|
100
|
+
OPENAI_MODEL: 'POPEYE_OPENAI_MODEL',
|
|
101
|
+
CONSENSUS_THRESHOLD: 'POPEYE_CONSENSUS_THRESHOLD',
|
|
102
|
+
MAX_DISAGREEMENTS: 'POPEYE_MAX_DISAGREEMENTS',
|
|
103
|
+
LOG_LEVEL: 'POPEYE_LOG_LEVEL',
|
|
104
|
+
} as const;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* CLI version
|
|
108
|
+
*/
|
|
109
|
+
export const CLI_VERSION = '1.0.0';
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* State file version
|
|
113
|
+
*/
|
|
114
|
+
export const STATE_VERSION = '1.0.0';
|