@outputai/cli 0.1.2-dev.0 → 0.1.2
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/package.json +7 -7
- package/dist/api/generated/api.d.ts +0 -820
- package/dist/api/generated/api.js +0 -226
- package/dist/api/http_client.d.ts +0 -27
- package/dist/api/http_client.js +0 -71
- package/dist/api/orval_post_process.d.ts +0 -11
- package/dist/api/orval_post_process.js +0 -46
- package/dist/api/parser.d.ts +0 -17
- package/dist/api/parser.js +0 -68
- package/dist/assets/config/costs.yml +0 -309
- package/dist/assets/docker/docker-compose-dev.yml +0 -146
- package/dist/commands/credentials/edit.d.ts +0 -10
- package/dist/commands/credentials/edit.js +0 -67
- package/dist/commands/credentials/edit.spec.d.ts +0 -1
- package/dist/commands/credentials/edit.spec.js +0 -73
- package/dist/commands/credentials/get.d.ts +0 -13
- package/dist/commands/credentials/get.js +0 -46
- package/dist/commands/credentials/get.spec.d.ts +0 -1
- package/dist/commands/credentials/get.spec.js +0 -74
- package/dist/commands/credentials/init.d.ts +0 -11
- package/dist/commands/credentials/init.js +0 -45
- package/dist/commands/credentials/init.spec.d.ts +0 -1
- package/dist/commands/credentials/init.spec.js +0 -68
- package/dist/commands/credentials/show.d.ts +0 -10
- package/dist/commands/credentials/show.js +0 -33
- package/dist/commands/credentials/show.spec.d.ts +0 -1
- package/dist/commands/credentials/show.spec.js +0 -57
- package/dist/commands/dev/eject.d.ts +0 -11
- package/dist/commands/dev/eject.js +0 -58
- package/dist/commands/dev/eject.spec.d.ts +0 -1
- package/dist/commands/dev/eject.spec.js +0 -109
- package/dist/commands/dev/index.d.ts +0 -13
- package/dist/commands/dev/index.js +0 -162
- package/dist/commands/dev/index.spec.d.ts +0 -1
- package/dist/commands/dev/index.spec.js +0 -239
- package/dist/commands/init.d.ts +0 -12
- package/dist/commands/init.js +0 -37
- package/dist/commands/init.spec.d.ts +0 -1
- package/dist/commands/init.spec.js +0 -100
- package/dist/commands/update.d.ts +0 -14
- package/dist/commands/update.js +0 -120
- package/dist/commands/update.spec.d.ts +0 -1
- package/dist/commands/update.spec.js +0 -178
- package/dist/commands/workflow/cost.d.ts +0 -16
- package/dist/commands/workflow/cost.js +0 -71
- package/dist/commands/workflow/cost.spec.d.ts +0 -1
- package/dist/commands/workflow/cost.spec.js +0 -47
- package/dist/commands/workflow/dataset/generate.d.ts +0 -22
- package/dist/commands/workflow/dataset/generate.js +0 -143
- package/dist/commands/workflow/dataset/list.d.ts +0 -12
- package/dist/commands/workflow/dataset/list.js +0 -87
- package/dist/commands/workflow/debug.d.ts +0 -16
- package/dist/commands/workflow/debug.js +0 -60
- package/dist/commands/workflow/debug.spec.d.ts +0 -1
- package/dist/commands/workflow/debug.spec.js +0 -34
- package/dist/commands/workflow/generate.d.ts +0 -17
- package/dist/commands/workflow/generate.js +0 -85
- package/dist/commands/workflow/generate.spec.d.ts +0 -1
- package/dist/commands/workflow/generate.spec.js +0 -115
- package/dist/commands/workflow/list.d.ts +0 -22
- package/dist/commands/workflow/list.js +0 -152
- package/dist/commands/workflow/list.spec.d.ts +0 -1
- package/dist/commands/workflow/list.spec.js +0 -99
- package/dist/commands/workflow/plan.d.ts +0 -12
- package/dist/commands/workflow/plan.js +0 -66
- package/dist/commands/workflow/plan.spec.d.ts +0 -1
- package/dist/commands/workflow/plan.spec.js +0 -341
- package/dist/commands/workflow/reset.d.ts +0 -14
- package/dist/commands/workflow/reset.js +0 -51
- package/dist/commands/workflow/result.d.ts +0 -13
- package/dist/commands/workflow/result.js +0 -46
- package/dist/commands/workflow/result.spec.d.ts +0 -1
- package/dist/commands/workflow/result.spec.js +0 -23
- package/dist/commands/workflow/run.d.ts +0 -16
- package/dist/commands/workflow/run.js +0 -97
- package/dist/commands/workflow/run.spec.d.ts +0 -1
- package/dist/commands/workflow/run.spec.js +0 -110
- package/dist/commands/workflow/runs/list.d.ts +0 -14
- package/dist/commands/workflow/runs/list.js +0 -104
- package/dist/commands/workflow/start.d.ts +0 -15
- package/dist/commands/workflow/start.js +0 -62
- package/dist/commands/workflow/start.spec.d.ts +0 -1
- package/dist/commands/workflow/start.spec.js +0 -28
- package/dist/commands/workflow/status.d.ts +0 -13
- package/dist/commands/workflow/status.js +0 -57
- package/dist/commands/workflow/status.spec.d.ts +0 -1
- package/dist/commands/workflow/status.spec.js +0 -33
- package/dist/commands/workflow/stop.d.ts +0 -10
- package/dist/commands/workflow/stop.js +0 -31
- package/dist/commands/workflow/stop.spec.d.ts +0 -1
- package/dist/commands/workflow/stop.spec.js +0 -17
- package/dist/commands/workflow/terminate.d.ts +0 -13
- package/dist/commands/workflow/terminate.js +0 -39
- package/dist/commands/workflow/test_eval.d.ts +0 -20
- package/dist/commands/workflow/test_eval.js +0 -151
- package/dist/config.d.ts +0 -47
- package/dist/config.js +0 -47
- package/dist/generated/framework_version.json +0 -3
- package/dist/hooks/init.d.ts +0 -3
- package/dist/hooks/init.js +0 -30
- package/dist/hooks/init.spec.d.ts +0 -1
- package/dist/hooks/init.spec.js +0 -54
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/index.spec.d.ts +0 -1
- package/dist/index.spec.js +0 -6
- package/dist/services/claude_client.d.ts +0 -30
- package/dist/services/claude_client.integration.test.d.ts +0 -1
- package/dist/services/claude_client.integration.test.js +0 -43
- package/dist/services/claude_client.js +0 -215
- package/dist/services/claude_client.spec.d.ts +0 -1
- package/dist/services/claude_client.spec.js +0 -145
- package/dist/services/coding_agents.d.ts +0 -36
- package/dist/services/coding_agents.js +0 -236
- package/dist/services/coding_agents.spec.d.ts +0 -1
- package/dist/services/coding_agents.spec.js +0 -256
- package/dist/services/copy_assets.spec.d.ts +0 -1
- package/dist/services/copy_assets.spec.js +0 -22
- package/dist/services/cost_calculator.d.ts +0 -18
- package/dist/services/cost_calculator.js +0 -359
- package/dist/services/cost_calculator.spec.d.ts +0 -1
- package/dist/services/cost_calculator.spec.js +0 -540
- package/dist/services/credentials_service.d.ts +0 -12
- package/dist/services/credentials_service.integration.test.d.ts +0 -1
- package/dist/services/credentials_service.integration.test.js +0 -66
- package/dist/services/credentials_service.js +0 -64
- package/dist/services/credentials_service.spec.d.ts +0 -1
- package/dist/services/credentials_service.spec.js +0 -106
- package/dist/services/datasets.d.ts +0 -20
- package/dist/services/datasets.js +0 -132
- package/dist/services/docker.d.ts +0 -38
- package/dist/services/docker.js +0 -148
- package/dist/services/docker.spec.d.ts +0 -1
- package/dist/services/docker.spec.js +0 -124
- package/dist/services/env_configurator.d.ts +0 -15
- package/dist/services/env_configurator.js +0 -163
- package/dist/services/env_configurator.spec.d.ts +0 -1
- package/dist/services/env_configurator.spec.js +0 -192
- package/dist/services/generate_plan_name@v1.prompt +0 -24
- package/dist/services/messages.d.ts +0 -9
- package/dist/services/messages.js +0 -338
- package/dist/services/messages.spec.d.ts +0 -1
- package/dist/services/messages.spec.js +0 -55
- package/dist/services/npm_update_service.d.ts +0 -6
- package/dist/services/npm_update_service.js +0 -87
- package/dist/services/npm_update_service.spec.d.ts +0 -1
- package/dist/services/npm_update_service.spec.js +0 -104
- package/dist/services/project_scaffold.d.ts +0 -31
- package/dist/services/project_scaffold.js +0 -212
- package/dist/services/project_scaffold.spec.d.ts +0 -1
- package/dist/services/project_scaffold.spec.js +0 -122
- package/dist/services/s3_trace_downloader.d.ts +0 -12
- package/dist/services/s3_trace_downloader.js +0 -57
- package/dist/services/template_processor.d.ts +0 -14
- package/dist/services/template_processor.js +0 -57
- package/dist/services/trace_reader.d.ts +0 -16
- package/dist/services/trace_reader.js +0 -57
- package/dist/services/trace_reader.spec.d.ts +0 -1
- package/dist/services/trace_reader.spec.js +0 -78
- package/dist/services/version_check.d.ts +0 -6
- package/dist/services/version_check.js +0 -52
- package/dist/services/version_check.spec.d.ts +0 -1
- package/dist/services/version_check.spec.js +0 -106
- package/dist/services/workflow_builder.d.ts +0 -16
- package/dist/services/workflow_builder.js +0 -86
- package/dist/services/workflow_builder.spec.d.ts +0 -1
- package/dist/services/workflow_builder.spec.js +0 -165
- package/dist/services/workflow_generator.d.ts +0 -5
- package/dist/services/workflow_generator.js +0 -40
- package/dist/services/workflow_generator.spec.d.ts +0 -1
- package/dist/services/workflow_generator.spec.js +0 -77
- package/dist/services/workflow_planner.d.ts +0 -15
- package/dist/services/workflow_planner.js +0 -48
- package/dist/services/workflow_planner.spec.d.ts +0 -1
- package/dist/services/workflow_planner.spec.js +0 -122
- package/dist/services/workflow_runs.d.ts +0 -14
- package/dist/services/workflow_runs.js +0 -25
- package/dist/templates/agent_instructions/CLAUDE.md.template +0 -19
- package/dist/templates/agent_instructions/dotclaude/settings.json.template +0 -29
- package/dist/templates/project/.env.example.template +0 -9
- package/dist/templates/project/.gitignore.template +0 -35
- package/dist/templates/project/README.md.template +0 -100
- package/dist/templates/project/config/costs.yml.template +0 -29
- package/dist/templates/project/package.json.template +0 -25
- package/dist/templates/project/src/clients/jina.ts.template +0 -30
- package/dist/templates/project/src/shared/utils/string.ts.template +0 -3
- package/dist/templates/project/src/shared/utils/url.ts.template +0 -15
- package/dist/templates/project/src/workflows/blog_evaluator/evaluators.ts.template +0 -23
- package/dist/templates/project/src/workflows/blog_evaluator/prompts/signal_noise@v1.prompt.template +0 -26
- package/dist/templates/project/src/workflows/blog_evaluator/scenarios/paulgraham_hwh.json.template +0 -3
- package/dist/templates/project/src/workflows/blog_evaluator/steps.ts.template +0 -27
- package/dist/templates/project/src/workflows/blog_evaluator/types.ts.template +0 -30
- package/dist/templates/project/src/workflows/blog_evaluator/utils.ts.template +0 -15
- package/dist/templates/project/src/workflows/blog_evaluator/workflow.ts.template +0 -27
- package/dist/templates/project/tsconfig.json.template +0 -20
- package/dist/templates/workflow/README.md.template +0 -216
- package/dist/templates/workflow/evaluators.ts.template +0 -21
- package/dist/templates/workflow/prompts/example@v1.prompt.template +0 -15
- package/dist/templates/workflow/scenarios/test_input.json.template +0 -3
- package/dist/templates/workflow/steps.ts.template +0 -20
- package/dist/templates/workflow/types.ts.template +0 -13
- package/dist/templates/workflow/workflow.ts.template +0 -23
- package/dist/test_helpers/mocks.d.ts +0 -38
- package/dist/test_helpers/mocks.js +0 -77
- package/dist/types/cost.d.ts +0 -149
- package/dist/types/cost.js +0 -6
- package/dist/types/domain.d.ts +0 -20
- package/dist/types/domain.js +0 -4
- package/dist/types/errors.d.ts +0 -68
- package/dist/types/errors.js +0 -100
- package/dist/types/errors.spec.d.ts +0 -1
- package/dist/types/errors.spec.js +0 -18
- package/dist/types/generator.d.ts +0 -26
- package/dist/types/generator.js +0 -1
- package/dist/types/trace.d.ts +0 -161
- package/dist/types/trace.js +0 -18
- package/dist/utils/claude.d.ts +0 -5
- package/dist/utils/claude.js +0 -19
- package/dist/utils/claude.spec.d.ts +0 -1
- package/dist/utils/claude.spec.js +0 -119
- package/dist/utils/constants.d.ts +0 -5
- package/dist/utils/constants.js +0 -4
- package/dist/utils/cost_formatter.d.ts +0 -5
- package/dist/utils/cost_formatter.js +0 -218
- package/dist/utils/date_formatter.d.ts +0 -23
- package/dist/utils/date_formatter.js +0 -49
- package/dist/utils/env_loader.d.ts +0 -1
- package/dist/utils/env_loader.js +0 -22
- package/dist/utils/env_loader.spec.d.ts +0 -1
- package/dist/utils/env_loader.spec.js +0 -43
- package/dist/utils/error_handler.d.ts +0 -8
- package/dist/utils/error_handler.js +0 -71
- package/dist/utils/error_utils.d.ts +0 -24
- package/dist/utils/error_utils.js +0 -87
- package/dist/utils/file_system.d.ts +0 -3
- package/dist/utils/file_system.js +0 -33
- package/dist/utils/format_workflow_result.d.ts +0 -5
- package/dist/utils/format_workflow_result.js +0 -18
- package/dist/utils/format_workflow_result.spec.d.ts +0 -1
- package/dist/utils/format_workflow_result.spec.js +0 -81
- package/dist/utils/framework_version.d.ts +0 -4
- package/dist/utils/framework_version.js +0 -4
- package/dist/utils/framework_version.spec.d.ts +0 -1
- package/dist/utils/framework_version.spec.js +0 -13
- package/dist/utils/header_utils.d.ts +0 -12
- package/dist/utils/header_utils.js +0 -29
- package/dist/utils/header_utils.spec.d.ts +0 -1
- package/dist/utils/header_utils.spec.js +0 -52
- package/dist/utils/input_parser.d.ts +0 -1
- package/dist/utils/input_parser.js +0 -19
- package/dist/utils/output_formatter.d.ts +0 -2
- package/dist/utils/output_formatter.js +0 -11
- package/dist/utils/paths.d.ts +0 -25
- package/dist/utils/paths.js +0 -36
- package/dist/utils/process.d.ts +0 -4
- package/dist/utils/process.js +0 -50
- package/dist/utils/resolve_input.d.ts +0 -1
- package/dist/utils/resolve_input.js +0 -22
- package/dist/utils/scenario_resolver.d.ts +0 -9
- package/dist/utils/scenario_resolver.js +0 -93
- package/dist/utils/scenario_resolver.spec.d.ts +0 -1
- package/dist/utils/scenario_resolver.spec.js +0 -214
- package/dist/utils/secret_sanitizer.d.ts +0 -1
- package/dist/utils/secret_sanitizer.js +0 -29
- package/dist/utils/sleep.d.ts +0 -5
- package/dist/utils/sleep.js +0 -5
- package/dist/utils/template.d.ts +0 -9
- package/dist/utils/template.js +0 -30
- package/dist/utils/template.spec.d.ts +0 -1
- package/dist/utils/template.spec.js +0 -77
- package/dist/utils/trace_extractor.d.ts +0 -27
- package/dist/utils/trace_extractor.js +0 -53
- package/dist/utils/trace_formatter.d.ts +0 -11
- package/dist/utils/trace_formatter.js +0 -402
- package/dist/utils/validation.d.ts +0 -13
- package/dist/utils/validation.js +0 -25
- package/dist/utils/validation.spec.d.ts +0 -1
- package/dist/utils/validation.spec.js +0 -140
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import { input, confirm, password } from '@inquirer/prompts';
|
|
2
|
-
import fs from 'node:fs/promises';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import { ux } from '@oclif/core';
|
|
5
|
-
import { getErrorMessage } from '#utils/error_utils.js';
|
|
6
|
-
import { UserCancelledError } from '#types/errors.js';
|
|
7
|
-
const COMMENT_LINE = /^\s*#/;
|
|
8
|
-
const COMMENTED_VAR = /^\s*#\s*([A-Z_][A-Z0-9_]*)\s*=\s*(.*)$/;
|
|
9
|
-
const ACTIVE_VAR = /^\s*([A-Z_][A-Z0-9_]*)\s*=\s*(.*)$/;
|
|
10
|
-
const VAR_IN_COMMENT = /^\s*#\s*[A-Z_]+=/;
|
|
11
|
-
const SECRET_MARKER = '<SECRET>';
|
|
12
|
-
function extractDescription(commentLine) {
|
|
13
|
-
return commentLine.replace(/^\s*#\s*/, '').trim();
|
|
14
|
-
}
|
|
15
|
-
function isSecret(value) {
|
|
16
|
-
return value.trim() === SECRET_MARKER;
|
|
17
|
-
}
|
|
18
|
-
function createEnvVariable(match, options) {
|
|
19
|
-
return {
|
|
20
|
-
key: match[1],
|
|
21
|
-
value: match[2],
|
|
22
|
-
description: options.lastComment ? extractDescription(options.lastComment) : undefined,
|
|
23
|
-
lineNumber: options.lineNumber,
|
|
24
|
-
isCommented: options.isCommented,
|
|
25
|
-
originalLine: options.line,
|
|
26
|
-
isSecret: isSecret(match[2])
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
async function parseEnvFile(filePath) {
|
|
30
|
-
const content = await fs.readFile(filePath, 'utf-8');
|
|
31
|
-
const lines = content.split('\n');
|
|
32
|
-
// Use an object to track state without reassigning
|
|
33
|
-
const state = { lastComment: null };
|
|
34
|
-
const variables = [];
|
|
35
|
-
lines.forEach((line, i) => {
|
|
36
|
-
// Check if line is a comment (but not a commented-out variable)
|
|
37
|
-
if (line.match(COMMENT_LINE) && !line.match(VAR_IN_COMMENT)) {
|
|
38
|
-
state.lastComment = line;
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
// Check for commented-out variable
|
|
42
|
-
const commentedMatch = line.match(COMMENTED_VAR);
|
|
43
|
-
if (commentedMatch) {
|
|
44
|
-
variables.push(createEnvVariable(commentedMatch, {
|
|
45
|
-
lineNumber: i,
|
|
46
|
-
line,
|
|
47
|
-
isCommented: true,
|
|
48
|
-
lastComment: state.lastComment
|
|
49
|
-
}));
|
|
50
|
-
state.lastComment = null;
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
// Check for active variable
|
|
54
|
-
const activeMatch = line.match(ACTIVE_VAR);
|
|
55
|
-
if (activeMatch) {
|
|
56
|
-
variables.push(createEnvVariable(activeMatch, {
|
|
57
|
-
lineNumber: i,
|
|
58
|
-
line,
|
|
59
|
-
isCommented: false,
|
|
60
|
-
lastComment: state.lastComment
|
|
61
|
-
}));
|
|
62
|
-
state.lastComment = null;
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
// Reset lastComment if we hit a blank line or non-comment line
|
|
66
|
-
if (line.trim() === '' || !line.match(COMMENT_LINE)) {
|
|
67
|
-
state.lastComment = null;
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
return variables;
|
|
71
|
-
}
|
|
72
|
-
const isEmpty = (value) => value.trim() === '';
|
|
73
|
-
const promptForVariables = async (variables) => variables.reduce(async (accPromise, variable) => {
|
|
74
|
-
const acc = await accPromise;
|
|
75
|
-
// Skip if value is not empty and not a secret marker
|
|
76
|
-
if (!isEmpty(variable.value) && !variable.isSecret) {
|
|
77
|
-
return [...acc, variable];
|
|
78
|
-
}
|
|
79
|
-
const description = variable.description ? ` (${variable.description})` : '';
|
|
80
|
-
// Use password prompt for secrets, regular input for others
|
|
81
|
-
const newValue = variable.isSecret ?
|
|
82
|
-
await password({
|
|
83
|
-
message: `${variable.key}${description} (secret):`,
|
|
84
|
-
mask: true
|
|
85
|
-
}) :
|
|
86
|
-
await input({
|
|
87
|
-
message: `${variable.key}${description}:`,
|
|
88
|
-
default: ''
|
|
89
|
-
});
|
|
90
|
-
return [
|
|
91
|
-
...acc,
|
|
92
|
-
{
|
|
93
|
-
...variable,
|
|
94
|
-
value: newValue,
|
|
95
|
-
isCommented: newValue ? false : variable.isCommented,
|
|
96
|
-
isSecret: false // Clear the secret flag after getting the actual value
|
|
97
|
-
}
|
|
98
|
-
];
|
|
99
|
-
}, Promise.resolve([]));
|
|
100
|
-
async function writeEnvFile(filePath, variables) {
|
|
101
|
-
const content = await fs.readFile(filePath, 'utf-8');
|
|
102
|
-
const lines = content.split('\n');
|
|
103
|
-
const variableMap = new Map(variables.map(v => [v.lineNumber, v]));
|
|
104
|
-
const outputLines = lines.map((line, i) => {
|
|
105
|
-
const variable = variableMap.get(i);
|
|
106
|
-
if (variable) {
|
|
107
|
-
// Reconstruct the variable line
|
|
108
|
-
return `${variable.isCommented ? '# ' : ''}${variable.key}=${variable.value}`;
|
|
109
|
-
}
|
|
110
|
-
// Preserve other lines (comments, blank lines, etc.)
|
|
111
|
-
return line;
|
|
112
|
-
});
|
|
113
|
-
await fs.writeFile(filePath, outputLines.join('\n'), 'utf-8');
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Interactively configures environment variables for a project by prompting the user
|
|
117
|
-
* to provide values for empty variables or variables marked as secrets.
|
|
118
|
-
*
|
|
119
|
-
* This function reads from .env.example and, when the user confirms configuration,
|
|
120
|
-
* copies it to .env before prompting for values. The .env.example file remains
|
|
121
|
-
* unchanged as a template for other developers.
|
|
122
|
-
*
|
|
123
|
-
* @param projectPath - The absolute path to the project directory containing the .env.example file
|
|
124
|
-
* @param skipPrompt - If true, copies .env.example to .env without interactive prompts and returns false
|
|
125
|
-
* @returns A promise that resolves to true if environment variables were successfully configured,
|
|
126
|
-
* false if configuration was skipped (no .env.example file, user declined, no variables to configure,
|
|
127
|
-
* or an error occurred)
|
|
128
|
-
*/
|
|
129
|
-
export async function configureEnvironmentVariables(projectPath, skipPrompt = false) {
|
|
130
|
-
try {
|
|
131
|
-
ux.stdout('configuring environment variables...');
|
|
132
|
-
const envExamplePath = path.join(projectPath, '.env.example');
|
|
133
|
-
const envPath = path.join(projectPath, '.env');
|
|
134
|
-
// Copy .env.example to .env before configuring
|
|
135
|
-
await fs.copyFile(envExamplePath, envPath);
|
|
136
|
-
if (skipPrompt) {
|
|
137
|
-
return false;
|
|
138
|
-
}
|
|
139
|
-
const shouldConfigure = await confirm({
|
|
140
|
-
message: 'Would you like to configure environment variables now?',
|
|
141
|
-
default: true
|
|
142
|
-
});
|
|
143
|
-
if (!shouldConfigure) {
|
|
144
|
-
return false;
|
|
145
|
-
}
|
|
146
|
-
const variables = await parseEnvFile(envPath);
|
|
147
|
-
const variablesToConfigure = variables.filter(v => isEmpty(v.value) || v.isSecret);
|
|
148
|
-
if (variablesToConfigure.length === 0) {
|
|
149
|
-
return false;
|
|
150
|
-
}
|
|
151
|
-
const updated = await promptForVariables(variables);
|
|
152
|
-
await writeEnvFile(envPath, updated);
|
|
153
|
-
return true;
|
|
154
|
-
}
|
|
155
|
-
catch (error) {
|
|
156
|
-
// Ctrl+C in @inquirer/prompts throws ExitPromptError - propagate as UserCancelledError
|
|
157
|
-
if (error instanceof Error && error.name === 'ExitPromptError') {
|
|
158
|
-
throw new UserCancelledError();
|
|
159
|
-
}
|
|
160
|
-
ux.warn(`Failed to configure environment variables: ${getErrorMessage(error)}`);
|
|
161
|
-
return false;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import fs from 'node:fs/promises';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import { configureEnvironmentVariables } from './env_configurator.js';
|
|
5
|
-
// Mock inquirer prompts
|
|
6
|
-
vi.mock('@inquirer/prompts', () => ({
|
|
7
|
-
input: vi.fn(),
|
|
8
|
-
confirm: vi.fn(),
|
|
9
|
-
password: vi.fn()
|
|
10
|
-
}));
|
|
11
|
-
describe('configureEnvironmentVariables', () => {
|
|
12
|
-
const testState = { tempDir: '', envExamplePath: '', envPath: '' };
|
|
13
|
-
beforeEach(async () => {
|
|
14
|
-
// Clear all mocks before each test
|
|
15
|
-
vi.clearAllMocks();
|
|
16
|
-
// Create temporary directory for test files
|
|
17
|
-
testState.tempDir = path.join('/tmp', `test-env-${Date.now()}`);
|
|
18
|
-
await fs.mkdir(testState.tempDir, { recursive: true });
|
|
19
|
-
testState.envExamplePath = path.join(testState.tempDir, '.env.example');
|
|
20
|
-
testState.envPath = path.join(testState.tempDir, '.env');
|
|
21
|
-
});
|
|
22
|
-
afterEach(async () => {
|
|
23
|
-
// Clean up temporary directory
|
|
24
|
-
try {
|
|
25
|
-
await fs.rm(testState.tempDir, { recursive: true, force: true });
|
|
26
|
-
}
|
|
27
|
-
catch {
|
|
28
|
-
// Ignore cleanup errors
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
it('should copy .env.example to .env when skipPrompt is true', async () => {
|
|
32
|
-
const envExampleContent = 'API_KEY=<SECRET>\nDATABASE_URL=localhost';
|
|
33
|
-
await fs.writeFile(testState.envExamplePath, envExampleContent);
|
|
34
|
-
const result = await configureEnvironmentVariables(testState.tempDir, true);
|
|
35
|
-
expect(result).toBe(false);
|
|
36
|
-
const envContent = await fs.readFile(testState.envPath, 'utf-8');
|
|
37
|
-
expect(envContent).toBe(envExampleContent);
|
|
38
|
-
});
|
|
39
|
-
it('should return false if .env.example file does not exist', async () => {
|
|
40
|
-
const result = await configureEnvironmentVariables(testState.tempDir, false);
|
|
41
|
-
expect(result).toBe(false);
|
|
42
|
-
});
|
|
43
|
-
it('should handle missing .env.example gracefully when skipPrompt is true', async () => {
|
|
44
|
-
const result = await configureEnvironmentVariables(testState.tempDir, true);
|
|
45
|
-
expect(result).toBe(false);
|
|
46
|
-
});
|
|
47
|
-
it('should return false if user declines configuration', async () => {
|
|
48
|
-
const { confirm } = await import('@inquirer/prompts');
|
|
49
|
-
vi.mocked(confirm).mockResolvedValue(false);
|
|
50
|
-
await fs.writeFile(testState.envExamplePath, '# API key\nAPIKEY=');
|
|
51
|
-
const result = await configureEnvironmentVariables(testState.tempDir, false);
|
|
52
|
-
expect(result).toBe(false);
|
|
53
|
-
expect(vi.mocked(confirm)).toHaveBeenCalled();
|
|
54
|
-
});
|
|
55
|
-
it('should return false if no empty variables exist', async () => {
|
|
56
|
-
const { confirm } = await import('@inquirer/prompts');
|
|
57
|
-
vi.mocked(confirm).mockResolvedValue(true);
|
|
58
|
-
await fs.writeFile(testState.envExamplePath, 'APIKEY=my-secret-key');
|
|
59
|
-
const result = await configureEnvironmentVariables(testState.tempDir, false);
|
|
60
|
-
expect(result).toBe(false);
|
|
61
|
-
});
|
|
62
|
-
it('should copy .env.example to .env when user confirms configuration', async () => {
|
|
63
|
-
const { input, confirm } = await import('@inquirer/prompts');
|
|
64
|
-
vi.mocked(confirm).mockResolvedValue(true);
|
|
65
|
-
vi.mocked(input).mockResolvedValueOnce('sk-proj-123');
|
|
66
|
-
const originalContent = `# API key
|
|
67
|
-
APIKEY=`;
|
|
68
|
-
await fs.writeFile(testState.envExamplePath, originalContent);
|
|
69
|
-
await configureEnvironmentVariables(testState.tempDir, false);
|
|
70
|
-
// Both files should exist
|
|
71
|
-
await expect(fs.access(testState.envExamplePath)).resolves.toBeUndefined();
|
|
72
|
-
await expect(fs.access(testState.envPath)).resolves.toBeUndefined();
|
|
73
|
-
});
|
|
74
|
-
it('should write configured values to .env while leaving .env.example unchanged', async () => {
|
|
75
|
-
const { input, confirm } = await import('@inquirer/prompts');
|
|
76
|
-
vi.mocked(confirm).mockResolvedValue(true);
|
|
77
|
-
vi.mocked(input).mockResolvedValueOnce('sk-proj-123');
|
|
78
|
-
const originalContent = `# API key
|
|
79
|
-
APIKEY=`;
|
|
80
|
-
await fs.writeFile(testState.envExamplePath, originalContent);
|
|
81
|
-
const result = await configureEnvironmentVariables(testState.tempDir, false);
|
|
82
|
-
expect(result).toBe(true);
|
|
83
|
-
// .env should have the configured value
|
|
84
|
-
const envContent = await fs.readFile(testState.envPath, 'utf-8');
|
|
85
|
-
expect(envContent).toContain('APIKEY=sk-proj-123');
|
|
86
|
-
// .env.example should remain unchanged
|
|
87
|
-
const envExampleContent = await fs.readFile(testState.envExamplePath, 'utf-8');
|
|
88
|
-
expect(envExampleContent).toBe(originalContent);
|
|
89
|
-
});
|
|
90
|
-
it('should prompt for empty variables and update .env', async () => {
|
|
91
|
-
const { input, confirm } = await import('@inquirer/prompts');
|
|
92
|
-
vi.mocked(confirm).mockResolvedValue(true);
|
|
93
|
-
vi.mocked(input).mockResolvedValueOnce('sk-proj-123');
|
|
94
|
-
vi.mocked(input).mockResolvedValueOnce('');
|
|
95
|
-
await fs.writeFile(testState.envExamplePath, `# API key for Anthropic
|
|
96
|
-
ANTHROPIC_API_KEY=
|
|
97
|
-
|
|
98
|
-
# API key for OpenAI
|
|
99
|
-
OPENAI_API_KEY=`);
|
|
100
|
-
const result = await configureEnvironmentVariables(testState.tempDir, false);
|
|
101
|
-
expect(result).toBe(true);
|
|
102
|
-
// Verify file was updated
|
|
103
|
-
const content = await fs.readFile(testState.envPath, 'utf-8');
|
|
104
|
-
expect(content).toContain('ANTHROPIC_API_KEY=sk-proj-123');
|
|
105
|
-
expect(content).toContain('OPENAI_API_KEY=');
|
|
106
|
-
});
|
|
107
|
-
it('should preserve comments in .env file', async () => {
|
|
108
|
-
const { input, confirm } = await import('@inquirer/prompts');
|
|
109
|
-
vi.mocked(confirm).mockResolvedValue(true);
|
|
110
|
-
vi.mocked(input).mockResolvedValueOnce('test-key');
|
|
111
|
-
const originalContent = `# This is a comment
|
|
112
|
-
# API key configuration
|
|
113
|
-
APIKEY=
|
|
114
|
-
|
|
115
|
-
# Another comment
|
|
116
|
-
OTHER=value`;
|
|
117
|
-
await fs.writeFile(testState.envExamplePath, originalContent);
|
|
118
|
-
await configureEnvironmentVariables(testState.tempDir, false);
|
|
119
|
-
const content = await fs.readFile(testState.envPath, 'utf-8');
|
|
120
|
-
expect(content).toContain('# This is a comment');
|
|
121
|
-
expect(content).toContain('# API key configuration');
|
|
122
|
-
expect(content).toContain('# Another comment');
|
|
123
|
-
expect(content).toContain('OTHER=value');
|
|
124
|
-
});
|
|
125
|
-
it('should skip placeholder values and only prompt for truly empty variables', async () => {
|
|
126
|
-
const { input, confirm } = await import('@inquirer/prompts');
|
|
127
|
-
vi.mocked(confirm).mockResolvedValue(true);
|
|
128
|
-
vi.mocked(input).mockResolvedValueOnce('new-key');
|
|
129
|
-
await fs.writeFile(testState.envExamplePath, `APIKEY=your_api_key_here
|
|
130
|
-
EMPTY_KEY=`);
|
|
131
|
-
const result = await configureEnvironmentVariables(testState.tempDir, false);
|
|
132
|
-
expect(result).toBe(true);
|
|
133
|
-
expect(vi.mocked(input)).toHaveBeenCalledTimes(1);
|
|
134
|
-
expect(vi.mocked(input)).toHaveBeenCalledWith(expect.objectContaining({
|
|
135
|
-
message: expect.stringContaining('EMPTY_KEY')
|
|
136
|
-
}));
|
|
137
|
-
});
|
|
138
|
-
it('should skip variables with existing values', async () => {
|
|
139
|
-
const { input, confirm } = await import('@inquirer/prompts');
|
|
140
|
-
vi.mocked(confirm).mockResolvedValue(true);
|
|
141
|
-
vi.mocked(input).mockResolvedValueOnce('new-key');
|
|
142
|
-
await fs.writeFile(testState.envExamplePath, `EXISTING_KEY=existing-value
|
|
143
|
-
|
|
144
|
-
EMPTY_KEY=`);
|
|
145
|
-
await configureEnvironmentVariables(testState.tempDir, false);
|
|
146
|
-
// Should only prompt for EMPTY_KEY, not EXISTING_KEY
|
|
147
|
-
expect(vi.mocked(input)).toHaveBeenCalledTimes(1);
|
|
148
|
-
});
|
|
149
|
-
it('should handle case where .env already exists (overwrite with copy)', async () => {
|
|
150
|
-
const { input, confirm } = await import('@inquirer/prompts');
|
|
151
|
-
vi.mocked(confirm).mockResolvedValue(true);
|
|
152
|
-
vi.mocked(input).mockResolvedValueOnce('new-configured-value');
|
|
153
|
-
// Create existing .env with old content
|
|
154
|
-
await fs.writeFile(testState.envPath, 'OLD_KEY=old-value');
|
|
155
|
-
// Create .env.example with new content
|
|
156
|
-
await fs.writeFile(testState.envExamplePath, 'NEW_KEY=');
|
|
157
|
-
const result = await configureEnvironmentVariables(testState.tempDir, false);
|
|
158
|
-
expect(result).toBe(true);
|
|
159
|
-
// .env should be overwritten with .env.example content and configured values
|
|
160
|
-
const envContent = await fs.readFile(testState.envPath, 'utf-8');
|
|
161
|
-
expect(envContent).toContain('NEW_KEY=new-configured-value');
|
|
162
|
-
expect(envContent).not.toContain('OLD_KEY');
|
|
163
|
-
});
|
|
164
|
-
it('should return false if an error occurs during parsing', async () => {
|
|
165
|
-
const { confirm } = await import('@inquirer/prompts');
|
|
166
|
-
vi.mocked(confirm).mockResolvedValue(true);
|
|
167
|
-
await fs.writeFile(testState.envExamplePath, 'KEY=');
|
|
168
|
-
// Delete the .env.example file after access check but before parsing would happen
|
|
169
|
-
// We simulate this by deleting during the copy operation
|
|
170
|
-
const originalCopyFile = fs.copyFile;
|
|
171
|
-
vi.spyOn(fs, 'copyFile').mockImplementation(async () => {
|
|
172
|
-
throw new Error('Copy failed');
|
|
173
|
-
});
|
|
174
|
-
const result = await configureEnvironmentVariables(testState.tempDir, false);
|
|
175
|
-
// Should return false when error occurs
|
|
176
|
-
expect(result).toBe(false);
|
|
177
|
-
// Restore original function
|
|
178
|
-
vi.mocked(fs.copyFile).mockImplementation(originalCopyFile);
|
|
179
|
-
});
|
|
180
|
-
it('should prompt for SECRET marker values with password input', async () => {
|
|
181
|
-
const { password, confirm } = await import('@inquirer/prompts');
|
|
182
|
-
vi.mocked(confirm).mockResolvedValue(true);
|
|
183
|
-
vi.mocked(password).mockResolvedValueOnce('my-secret-api-key');
|
|
184
|
-
await fs.writeFile(testState.envExamplePath, `# API Key
|
|
185
|
-
ANTHROPIC_API_KEY=<SECRET>`);
|
|
186
|
-
const result = await configureEnvironmentVariables(testState.tempDir, false);
|
|
187
|
-
expect(result).toBe(true);
|
|
188
|
-
expect(vi.mocked(password)).toHaveBeenCalledTimes(1);
|
|
189
|
-
const envContent = await fs.readFile(testState.envPath, 'utf-8');
|
|
190
|
-
expect(envContent).toContain('ANTHROPIC_API_KEY=my-secret-api-key');
|
|
191
|
-
});
|
|
192
|
-
});
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
provider: anthropic
|
|
3
|
-
model: claude-sonnet-4-20250514
|
|
4
|
-
temperature: 0.3
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
<assistant>
|
|
8
|
-
You are a semantic naming assistant. Generate concise, descriptive slugs for workflow plans.
|
|
9
|
-
</assistant>
|
|
10
|
-
|
|
11
|
-
<user>
|
|
12
|
-
Convert this workflow description into a short, semantic slug (2-6 words max):
|
|
13
|
-
|
|
14
|
-
"{{ description }}"
|
|
15
|
-
|
|
16
|
-
Requirements:
|
|
17
|
-
- Use snake_case format
|
|
18
|
-
- Be descriptive but concise
|
|
19
|
-
- Focus on the core action/purpose
|
|
20
|
-
- Use common technical terms
|
|
21
|
-
- Maximum 50 characters
|
|
22
|
-
|
|
23
|
-
Return ONLY the slug, no quotes, no explanation.
|
|
24
|
-
</user>
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Success and informational messages for project initialization
|
|
3
|
-
*/
|
|
4
|
-
export declare const getEjectSuccessMessage: (destPath: string, outputFile: string, binName: string) => string;
|
|
5
|
-
export declare const getProjectSuccessMessage: (folderName: string, installSuccess: boolean, envConfigured?: boolean) => string;
|
|
6
|
-
export declare const getWorkflowGenerateSuccessMessage: (workflowName: string, targetDir: string, filesCreated: string[]) => string;
|
|
7
|
-
export declare const getDevSuccessMessage: (services: Array<{
|
|
8
|
-
name: string;
|
|
9
|
-
}>) => string;
|