@solidactions/cli 1.23.1 → 1.24.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/dist/commands/ai-init.js +44 -29
- package/dist/commands/deploy.js +1 -1
- package/dist/commands/dev.js +25 -2
- package/dist/commands/docs-push.js +1 -1
- package/dist/commands/env-delete.js +18 -10
- package/dist/commands/env-list.js +40 -29
- package/dist/commands/env-pull.js +6 -4
- package/dist/commands/env-push.js +4 -4
- package/dist/commands/env-set.js +12 -3
- package/dist/commands/init.js +18 -1
- package/dist/commands/login.js +76 -20
- package/dist/commands/oauth-actions-list.js +1 -1
- package/dist/commands/oauth-actions-search.js +1 -1
- package/dist/commands/project-list.js +19 -13
- package/dist/commands/pull.js +16 -1
- package/dist/commands/role-push.js +3 -3
- package/dist/commands/run-list.js +24 -12
- package/dist/commands/run-start.js +7 -1
- package/dist/commands/run-view.js +5 -0
- package/dist/commands/skill-pull.js +1 -1
- package/dist/commands/skill-push.js +3 -3
- package/dist/index.js +29 -16
- package/dist/utils/api.js +70 -1
- package/dist/utils/config-write-target.js +16 -0
- package/dist/utils/config.js +17 -2
- package/dist/utils/env.js +15 -3
- package/dist/utils/mcp.js +15 -5
- package/dist/utils/table.js +62 -0
- package/package.json +1 -1
package/dist/commands/ai-init.js
CHANGED
|
@@ -3,6 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.NON_TTY_DEFAULT_NOTICE = void 0;
|
|
7
|
+
exports.resolveAiHelperTarget = resolveAiHelperTarget;
|
|
6
8
|
exports.aiInit = aiInit;
|
|
7
9
|
const fs_1 = __importDefault(require("fs"));
|
|
8
10
|
const chalk_1 = __importDefault(require("chalk"));
|
|
@@ -12,36 +14,49 @@ const path_1 = __importDefault(require("path"));
|
|
|
12
14
|
const github_1 = require("../utils/github");
|
|
13
15
|
const markers_1 = require("../utils/markers");
|
|
14
16
|
const skills_1 = require("../utils/skills");
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
17
|
+
exports.NON_TTY_DEFAULT_NOTICE = 'No --claude/--agents given and non-interactive — defaulting to CLAUDE.md; pass --agents for Codex/Cursor/Gemini.';
|
|
18
|
+
/**
|
|
19
|
+
* Resolve which AI-helper file (CLAUDE.md vs AGENTS.md) to target, WITHOUT
|
|
20
|
+
* touching the filesystem or network. Callers that also scaffold template
|
|
21
|
+
* files (e.g. `init`) must call this BEFORE writing anything, so a shell
|
|
22
|
+
* that can't answer the interactive prompt never leaves a half-scaffolded
|
|
23
|
+
* project — see the `init` half-scaffold bug this closes.
|
|
24
|
+
*/
|
|
25
|
+
async function resolveAiHelperTarget(options = {}) {
|
|
26
|
+
if (options.claude && options.agents) {
|
|
27
|
+
console.error(chalk_1.default.red('Please specify only one of --claude or --agents'));
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
if (options.claude) {
|
|
31
|
+
return 'CLAUDE.md';
|
|
32
|
+
}
|
|
33
|
+
if (options.agents) {
|
|
34
|
+
return 'AGENTS.md';
|
|
35
|
+
}
|
|
36
|
+
if (process.stdin.isTTY) {
|
|
37
|
+
const response = await (0, prompts_1.default)({
|
|
38
|
+
type: 'select',
|
|
39
|
+
name: 'file',
|
|
40
|
+
message: 'Which AI helper file?',
|
|
41
|
+
choices: [
|
|
42
|
+
{ title: 'CLAUDE.md (Claude Code)', value: 'CLAUDE.md' },
|
|
43
|
+
{ title: 'AGENTS.md (Codex, Cursor, Gemini, etc.)', value: 'AGENTS.md' },
|
|
44
|
+
],
|
|
45
|
+
});
|
|
46
|
+
if (!response.file) {
|
|
47
|
+
console.log(chalk_1.default.yellow('Cancelled.'));
|
|
48
|
+
process.exit(0);
|
|
44
49
|
}
|
|
50
|
+
return response.file;
|
|
51
|
+
}
|
|
52
|
+
// Non-TTY (CI, pipes, an AI agent's non-interactive shell) with no flag:
|
|
53
|
+
// never block on an unanswerable prompt — default instead.
|
|
54
|
+
console.log(chalk_1.default.yellow(exports.NON_TTY_DEFAULT_NOTICE));
|
|
55
|
+
return 'CLAUDE.md';
|
|
56
|
+
}
|
|
57
|
+
async function aiInit(options = {}, resolvedTarget) {
|
|
58
|
+
try {
|
|
59
|
+
const targetFile = resolvedTarget ?? await resolveAiHelperTarget(options);
|
|
45
60
|
console.log(chalk_1.default.blue('Fetching AI helper content...'));
|
|
46
61
|
// Fetch slim helper content for the chosen target.
|
|
47
62
|
const aiContent = await (0, skills_1.fetchAiHelperContent)(targetFile);
|
package/dist/commands/deploy.js
CHANGED
|
@@ -400,7 +400,7 @@ async function deploy(projectName, sourcePath, options = {}) {
|
|
|
400
400
|
if (status === 'deployed') {
|
|
401
401
|
clearInterval(poll);
|
|
402
402
|
console.log(chalk_1.default.green(`\n✓ Deployed to ${projectSlug}${envLabel}!`));
|
|
403
|
-
// Always sync YAML declarations (registers
|
|
403
|
+
// Always sync YAML declarations (registers variables and their mappings)
|
|
404
404
|
if (yamlConfig) {
|
|
405
405
|
await pushYamlDeclarations(config, projectSlug, yamlConfig);
|
|
406
406
|
}
|
package/dist/commands/dev.js
CHANGED
|
@@ -270,10 +270,13 @@ async function runDev(opts) {
|
|
|
270
270
|
// 3. Build ctx.vars from platform vars. A declared mapping is only readable
|
|
271
271
|
// on ctx.vars when it is an OAuth connection (with proxy fields) OR has a
|
|
272
272
|
// non-null resolved_value. Mappings with no value in this env are DROPPED
|
|
273
|
-
// — and must NOT be counted in the summary (BUG #1).
|
|
273
|
+
// — and must NOT be counted in the summary (BUG #1). A dropped SECRET is
|
|
274
|
+
// reported separately (it's genuinely unavailable to local dev, not
|
|
275
|
+
// merely "unset" — the platform never resolves secret values to the CLI).
|
|
274
276
|
const vars = {};
|
|
275
277
|
let connectionCount = 0;
|
|
276
278
|
let droppedCount = 0;
|
|
279
|
+
let droppedSecretCount = 0;
|
|
277
280
|
for (const pv of platformVars) {
|
|
278
281
|
if (pv.source_type === 'oauth_connection' && pv.proxy_url && pv.proxy_token && pv.connection_key) {
|
|
279
282
|
vars[pv.env_name] = {
|
|
@@ -286,6 +289,9 @@ async function runDev(opts) {
|
|
|
286
289
|
else if (pv.resolved_value != null) {
|
|
287
290
|
vars[pv.env_name] = pv.resolved_value;
|
|
288
291
|
}
|
|
292
|
+
else if (pv.is_secret) {
|
|
293
|
+
droppedSecretCount++;
|
|
294
|
+
}
|
|
289
295
|
else {
|
|
290
296
|
droppedCount++;
|
|
291
297
|
}
|
|
@@ -308,6 +314,9 @@ async function runDev(opts) {
|
|
|
308
314
|
if (droppedCount > 0) {
|
|
309
315
|
summary += ` (${droppedCount} declared ${droppedCount === 1 ? 'var' : 'vars'} had no value in this env and ${droppedCount === 1 ? 'was' : 'were'} skipped)`;
|
|
310
316
|
}
|
|
317
|
+
if (droppedSecretCount > 0) {
|
|
318
|
+
summary += ` (${droppedSecretCount} secret ${droppedSecretCount === 1 ? 'var is' : 'vars are'} not available to local dev — set a test value in your dev environment with \`solidactions env set\`, or pass values via \`-i\`.)`;
|
|
319
|
+
}
|
|
311
320
|
out(summary);
|
|
312
321
|
}
|
|
313
322
|
else {
|
|
@@ -326,7 +335,21 @@ async function runDev(opts) {
|
|
|
326
335
|
const entryPath = path_1.default.resolve(opts.entry);
|
|
327
336
|
const _require = (0, module_1.createRequire)(entryPath);
|
|
328
337
|
// Resolve via the installed (or linked) @solidactions/sdk package.
|
|
329
|
-
|
|
338
|
+
let sdkTestingMain;
|
|
339
|
+
try {
|
|
340
|
+
sdkTestingMain = _require.resolve('@solidactions/sdk/testing');
|
|
341
|
+
}
|
|
342
|
+
catch (e) {
|
|
343
|
+
if (e.code === 'MODULE_NOT_FOUND') {
|
|
344
|
+
err('Dependencies not installed — run `npm install` in the project directory first.');
|
|
345
|
+
return {
|
|
346
|
+
stdout: stdoutLines.join('\n'),
|
|
347
|
+
stderr: stderrLines.join('\n'),
|
|
348
|
+
result: { status: 'failed', error: e, phase: 'setup' },
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
throw e;
|
|
352
|
+
}
|
|
330
353
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
331
354
|
const { createMockServer } = _require(sdkTestingMain);
|
|
332
355
|
const mockServer = await createMockServer();
|
|
@@ -154,7 +154,7 @@ async function docsPushWithConfig(dir, options, config) {
|
|
|
154
154
|
mcpResult = await (0, mcp_1.callDocsTool)(config, 'docs_vault', callArgs);
|
|
155
155
|
}
|
|
156
156
|
catch (e) {
|
|
157
|
-
process.stderr.write(chalk_1.default.red(`error:
|
|
157
|
+
process.stderr.write(chalk_1.default.red(`error: ${e.message}\n`));
|
|
158
158
|
process.exit(1);
|
|
159
159
|
}
|
|
160
160
|
if (!mcpResult.ok) {
|
|
@@ -14,18 +14,20 @@ async function envDelete(keyOrProject, keyIfProject, options = {}) {
|
|
|
14
14
|
const isProjectMode = keyIfProject !== undefined;
|
|
15
15
|
const projectName = isProjectMode ? keyOrProject : undefined;
|
|
16
16
|
const key = isProjectMode ? keyIfProject : keyOrProject;
|
|
17
|
+
const environment = options.env ?? 'dev';
|
|
18
|
+
const projectSlug = projectName && environment === 'production' ? projectName : `${projectName}-${environment}`;
|
|
17
19
|
try {
|
|
18
20
|
if (isProjectMode) {
|
|
19
|
-
// Delete project variable
|
|
20
|
-
console.log(chalk_1.default.blue(`Deleting variable
|
|
21
|
-
// First, get the
|
|
22
|
-
const listResponse = await axios_1.default.get(`${config.host}/api/v1/projects/${
|
|
21
|
+
// Delete project variable
|
|
22
|
+
console.log(chalk_1.default.blue(`Deleting variable "${key}" from project "${projectName}" (${environment})...`));
|
|
23
|
+
// First, get the variable to find its ID
|
|
24
|
+
const listResponse = await axios_1.default.get(`${config.host}/api/v1/projects/${projectSlug}/variable-mappings`, {
|
|
23
25
|
headers: (0, api_1.getApiHeaders)(config),
|
|
24
26
|
});
|
|
25
27
|
const mappings = listResponse.data || [];
|
|
26
28
|
const mapping = mappings.find((m) => m.env_name === key);
|
|
27
29
|
if (!mapping) {
|
|
28
|
-
console.error(chalk_1.default.red(`Variable
|
|
30
|
+
console.error(chalk_1.default.red(`Variable "${key}" not found in project "${projectName}" (${environment}).`));
|
|
29
31
|
process.exit(1);
|
|
30
32
|
}
|
|
31
33
|
// Confirm deletion unless --yes flag is provided
|
|
@@ -35,7 +37,7 @@ async function envDelete(keyOrProject, keyIfProject, options = {}) {
|
|
|
35
37
|
name: 'confirm',
|
|
36
38
|
message: mapping.is_yaml_declared
|
|
37
39
|
? `Clear YAML-declared variable "${key}"? (The mapping will be preserved but value cleared)`
|
|
38
|
-
: `Delete variable
|
|
40
|
+
: `Delete variable "${key}" from project "${projectName}" (${environment})?`,
|
|
39
41
|
initial: false,
|
|
40
42
|
});
|
|
41
43
|
if (!response.confirm) {
|
|
@@ -44,14 +46,14 @@ async function envDelete(keyOrProject, keyIfProject, options = {}) {
|
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
48
|
// Delete the mapping
|
|
47
|
-
await axios_1.default.delete(`${config.host}/api/v1/projects/${
|
|
49
|
+
await axios_1.default.delete(`${config.host}/api/v1/projects/${projectSlug}/variable-mappings/${mapping.id}`, {
|
|
48
50
|
headers: (0, api_1.getApiHeaders)(config),
|
|
49
51
|
});
|
|
50
52
|
if (mapping.is_yaml_declared) {
|
|
51
|
-
console.log(chalk_1.default.green(`Variable
|
|
53
|
+
console.log(chalk_1.default.green(`Variable "${key}" cleared successfully.`));
|
|
52
54
|
}
|
|
53
55
|
else {
|
|
54
|
-
console.log(chalk_1.default.green(`Variable
|
|
56
|
+
console.log(chalk_1.default.green(`Variable "${key}" deleted successfully.`));
|
|
55
57
|
}
|
|
56
58
|
}
|
|
57
59
|
else {
|
|
@@ -93,7 +95,13 @@ async function envDelete(keyOrProject, keyIfProject, options = {}) {
|
|
|
93
95
|
console.error(chalk_1.default.red('Authentication failed. Run "solidactions login <api-key>" to re-configure.'));
|
|
94
96
|
}
|
|
95
97
|
else if (error.response.status === 404) {
|
|
96
|
-
|
|
98
|
+
if (isProjectMode) {
|
|
99
|
+
const envsList = await (0, api_1.describeProjectEnvironments)(config, projectName);
|
|
100
|
+
console.error(chalk_1.default.red(`Project "${projectName}" has no ${environment} environment${envsList ? ` (exists in: ${envsList})` : ''}.`));
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
console.error(chalk_1.default.red(`Variable "${key}" not found.`));
|
|
104
|
+
}
|
|
97
105
|
}
|
|
98
106
|
else {
|
|
99
107
|
console.error(chalk_1.default.red(`Failed: ${error.response.status}`), error.response.data);
|
|
@@ -7,6 +7,7 @@ exports.envList = envList;
|
|
|
7
7
|
const axios_1 = __importDefault(require("axios"));
|
|
8
8
|
const chalk_1 = __importDefault(require("chalk"));
|
|
9
9
|
const api_1 = require("../utils/api");
|
|
10
|
+
const table_1 = require("../utils/table");
|
|
10
11
|
/**
|
|
11
12
|
* Format a value for display, with inherited badge if applicable.
|
|
12
13
|
*/
|
|
@@ -28,73 +29,77 @@ function formatEnvValue(value, source, isSecret) {
|
|
|
28
29
|
}
|
|
29
30
|
async function envList(projectName, options = {}) {
|
|
30
31
|
const config = await (0, api_1.requireConfigWithWorkspace)();
|
|
32
|
+
const environment = options.env || 'dev';
|
|
31
33
|
try {
|
|
32
34
|
if (projectName) {
|
|
33
35
|
// List project variable mappings
|
|
34
|
-
const environment = options.env || 'dev';
|
|
35
36
|
const projectSlug = environment === 'production'
|
|
36
37
|
? projectName
|
|
37
38
|
: `${projectName}-${environment}`;
|
|
38
|
-
|
|
39
|
+
if (!options.json) {
|
|
40
|
+
console.log(chalk_1.default.blue(`Variables for project "${projectName}" (${environment}):`));
|
|
41
|
+
}
|
|
39
42
|
const response = await axios_1.default.get(`${config.host}/api/v1/projects/${projectSlug}/variable-mappings`, {
|
|
40
43
|
headers: (0, api_1.getApiHeaders)(config),
|
|
41
44
|
});
|
|
42
45
|
const mappings = response.data || [];
|
|
46
|
+
if (options.json) {
|
|
47
|
+
console.log(JSON.stringify(mappings, null, 2));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
43
50
|
if (mappings.length === 0) {
|
|
44
51
|
console.log(chalk_1.default.gray('No variable mappings found.'));
|
|
45
52
|
return;
|
|
46
53
|
}
|
|
47
54
|
console.log('');
|
|
48
|
-
|
|
49
|
-
console.log(chalk_1.default.gray('-'.repeat(90)));
|
|
50
|
-
for (const mapping of mappings) {
|
|
55
|
+
const rows = mappings.map((mapping) => {
|
|
51
56
|
const key = mapping.env_name || '?';
|
|
52
57
|
// Value display (resolved_value includes global/oauth resolution)
|
|
53
58
|
const rawValue = mapping.resolved_value ?? mapping.value;
|
|
54
|
-
|
|
55
|
-
if (mapping.is_secret) {
|
|
56
|
-
value = chalk_1.default.yellow('••••••');
|
|
57
|
-
}
|
|
58
|
-
else if (rawValue) {
|
|
59
|
-
value = rawValue.toString().substring(0, 22);
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
value = chalk_1.default.gray('-');
|
|
63
|
-
}
|
|
59
|
+
const value = mapping.is_secret ? '••••••' : rawValue ? rawValue.toString() : '-';
|
|
64
60
|
// Type & source (mirrors UI getMappingType)
|
|
65
61
|
let type;
|
|
66
62
|
let source;
|
|
67
63
|
if (mapping.source_type === 'oauth_connection' && mapping.oauth_connection_id) {
|
|
68
|
-
type =
|
|
69
|
-
source =
|
|
64
|
+
type = 'oauth';
|
|
65
|
+
source = mapping.oauth_connection_name || 'OAuth';
|
|
70
66
|
}
|
|
71
67
|
else if (mapping.global_variable_key) {
|
|
72
|
-
type =
|
|
73
|
-
source =
|
|
68
|
+
type = 'global';
|
|
69
|
+
source = mapping.global_variable_key;
|
|
74
70
|
}
|
|
75
71
|
else if (mapping.has_value) {
|
|
76
|
-
type =
|
|
77
|
-
source =
|
|
72
|
+
type = 'project var';
|
|
73
|
+
source = 'local';
|
|
78
74
|
}
|
|
79
75
|
else {
|
|
80
|
-
type =
|
|
81
|
-
source =
|
|
76
|
+
type = '-';
|
|
77
|
+
source = '-';
|
|
82
78
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
79
|
+
return [key, value, type, source];
|
|
80
|
+
});
|
|
81
|
+
const lines = (0, table_1.renderTable)(['KEY', 'VALUE', 'TYPE', 'SOURCE'], rows, { minWidths: [28, 24, 14, 0] });
|
|
82
|
+
console.log(chalk_1.default.gray(lines[0]));
|
|
83
|
+
console.log(chalk_1.default.gray(lines[1]));
|
|
84
|
+
for (const line of lines.slice(2)) {
|
|
85
|
+
console.log(line);
|
|
87
86
|
}
|
|
88
87
|
console.log('');
|
|
89
88
|
console.log(chalk_1.default.gray(`${mappings.length} variable(s)`));
|
|
90
89
|
}
|
|
91
90
|
else {
|
|
92
91
|
// List global variables with per-environment values
|
|
93
|
-
|
|
92
|
+
if (!options.json) {
|
|
93
|
+
console.log(chalk_1.default.blue('Global variables:'));
|
|
94
|
+
}
|
|
94
95
|
const response = await axios_1.default.get(`${config.host}/api/v1/variables`, {
|
|
95
96
|
headers: (0, api_1.getApiHeaders)(config),
|
|
96
97
|
});
|
|
97
98
|
const variables = response.data?.data || [];
|
|
99
|
+
if (options.json) {
|
|
100
|
+
console.log(JSON.stringify(variables, null, 2));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
98
103
|
if (variables.length === 0) {
|
|
99
104
|
console.log(chalk_1.default.gray('No global variables found.'));
|
|
100
105
|
return;
|
|
@@ -185,7 +190,13 @@ async function envList(projectName, options = {}) {
|
|
|
185
190
|
console.error(chalk_1.default.red('Authentication failed. Run "solidactions login <api-key>" to re-configure.'));
|
|
186
191
|
}
|
|
187
192
|
else if (error.response.status === 404) {
|
|
188
|
-
|
|
193
|
+
if (projectName) {
|
|
194
|
+
const envsList = await (0, api_1.describeProjectEnvironments)(config, projectName);
|
|
195
|
+
console.error(chalk_1.default.red(`Project "${projectName}" has no ${environment} environment${envsList ? ` (exists in: ${envsList})` : ''}.`));
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
console.error(chalk_1.default.red('Resource not found.'));
|
|
199
|
+
}
|
|
189
200
|
}
|
|
190
201
|
else {
|
|
191
202
|
console.error(chalk_1.default.red(`Failed: ${error.response.status}`), error.response.data);
|
|
@@ -35,7 +35,7 @@ async function envPull(projectName, options = {}) {
|
|
|
35
35
|
// Determine output file
|
|
36
36
|
const outputFile = options.output || (environment === 'production' ? '.env' : `.env.${environment}`);
|
|
37
37
|
const outputPath = path_1.default.resolve(outputFile);
|
|
38
|
-
console.log(chalk_1.default.blue(`Pulling
|
|
38
|
+
console.log(chalk_1.default.blue(`Pulling variables from "${projectName}" (${environment})...`));
|
|
39
39
|
try {
|
|
40
40
|
// First, check if there are any secrets
|
|
41
41
|
const checkResponse = await axios_1.default.get(`${config.host}/api/v1/projects/${projectSlug}/variable-mappings?resolve_oauth=true`, {
|
|
@@ -43,7 +43,7 @@ async function envPull(projectName, options = {}) {
|
|
|
43
43
|
});
|
|
44
44
|
const mappings = checkResponse.data || [];
|
|
45
45
|
if (mappings.length === 0) {
|
|
46
|
-
console.log(chalk_1.default.yellow('No
|
|
46
|
+
console.log(chalk_1.default.yellow('No variables found for this project.'));
|
|
47
47
|
process.exit(0);
|
|
48
48
|
}
|
|
49
49
|
// Check for secrets (skip confirmation for --update-oauth since OAuth tokens are always secrets)
|
|
@@ -68,7 +68,7 @@ async function envPull(projectName, options = {}) {
|
|
|
68
68
|
console.log(chalk_1.default.yellow('No OAuth variables found for this project.'));
|
|
69
69
|
process.exit(0);
|
|
70
70
|
}
|
|
71
|
-
// Build OAuth
|
|
71
|
+
// Build OAuth variable names set and their formatted lines
|
|
72
72
|
const oauthKeySet = new Set(oauthVars.map((v) => v.env_name));
|
|
73
73
|
const oauthLines = [];
|
|
74
74
|
for (const variable of oauthVars) {
|
|
@@ -146,7 +146,9 @@ async function envPull(projectName, options = {}) {
|
|
|
146
146
|
}
|
|
147
147
|
// Full pull: Build .env file content
|
|
148
148
|
const lines = [];
|
|
149
|
-
lines.push(`#
|
|
149
|
+
lines.push(`# Variables pulled from SolidActions for ${projectName} / ${environment}.`);
|
|
150
|
+
lines.push('# NOTE: this .env is NOT read by `solidactions dev`. Local dev vars come from');
|
|
151
|
+
lines.push('# the platform (dev fetches them with `-e <env>`); pass ad-hoc values with `-i`.');
|
|
150
152
|
lines.push(`# Generated by solidactions env pull on ${new Date().toISOString()}`);
|
|
151
153
|
lines.push('');
|
|
152
154
|
let count = 0;
|
|
@@ -37,7 +37,7 @@ async function envPush(projectName, sourcePath, options = {}) {
|
|
|
37
37
|
const envFilePath = path_1.default.join(sourceDir, envFileName);
|
|
38
38
|
if (!fs_1.default.existsSync(envFilePath)) {
|
|
39
39
|
console.error(chalk_1.default.red(`${envFileName} not found in ${sourceDir}`));
|
|
40
|
-
console.log(chalk_1.default.gray(`Create ${envFileName} with your
|
|
40
|
+
console.log(chalk_1.default.gray(`Create ${envFileName} with your variables, or use a different --env.`));
|
|
41
41
|
process.exit(1);
|
|
42
42
|
}
|
|
43
43
|
// Parse the .env file
|
|
@@ -53,7 +53,7 @@ async function envPush(projectName, sourcePath, options = {}) {
|
|
|
53
53
|
}
|
|
54
54
|
else {
|
|
55
55
|
if (declaredVars.size === 0) {
|
|
56
|
-
console.log(chalk_1.default.yellow('No
|
|
56
|
+
console.log(chalk_1.default.yellow('No variables declared in solidactions.yaml.'));
|
|
57
57
|
console.log(chalk_1.default.gray('Use --include-undeclared to push all vars from the .env file.'));
|
|
58
58
|
process.exit(0);
|
|
59
59
|
}
|
|
@@ -85,7 +85,7 @@ async function envPush(projectName, sourcePath, options = {}) {
|
|
|
85
85
|
const projectSlug = environment === 'production'
|
|
86
86
|
? projectName
|
|
87
87
|
: `${projectName}-${environment}`;
|
|
88
|
-
console.log(chalk_1.default.blue(`Pushing
|
|
88
|
+
console.log(chalk_1.default.blue(`Pushing variables to "${projectName}" (${environment})...`));
|
|
89
89
|
// Fetch current server state
|
|
90
90
|
let serverMappings = [];
|
|
91
91
|
try {
|
|
@@ -200,7 +200,7 @@ async function envPush(projectName, sourcePath, options = {}) {
|
|
|
200
200
|
console.log(chalk_1.default.gray(` ${created} created, ${updated} updated` + (toSkip.length > 0 ? `, ${toSkip.length} skipped` : '')));
|
|
201
201
|
}
|
|
202
202
|
catch (error) {
|
|
203
|
-
console.error(chalk_1.default.red('Failed to push
|
|
203
|
+
console.error(chalk_1.default.red('Failed to push variables:'), error.response?.data?.message || error.message);
|
|
204
204
|
process.exit(1);
|
|
205
205
|
}
|
|
206
206
|
}
|
package/dist/commands/env-set.js
CHANGED
|
@@ -49,6 +49,10 @@ async function envSet(keyOrProject, valueOrKey, valueIfProject, options = {}) {
|
|
|
49
49
|
const projectName = keyOrProject;
|
|
50
50
|
const key = valueOrKey;
|
|
51
51
|
const value = valueIfProject;
|
|
52
|
+
if (!(0, env_1.isValidEnvName)(key)) {
|
|
53
|
+
console.error(chalk_1.default.red((0, env_1.envNameError)(key)));
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
52
56
|
if ((0, env_1.isReservedEnvName)(key)) {
|
|
53
57
|
console.error(chalk_1.default.red((0, env_1.reservedEnvNameError)(key)));
|
|
54
58
|
process.exit(1);
|
|
@@ -105,10 +109,11 @@ async function envSet(keyOrProject, valueOrKey, valueIfProject, options = {}) {
|
|
|
105
109
|
console.error(chalk_1.default.red('Authentication failed. Run "solidactions login <api-key>" to re-configure.'));
|
|
106
110
|
}
|
|
107
111
|
else if (error.response.status === 404) {
|
|
108
|
-
|
|
112
|
+
const envsList = await (0, api_1.describeProjectEnvironments)(config, projectName);
|
|
113
|
+
console.error(chalk_1.default.red(`Project "${projectName}" has no ${environment} environment${envsList ? ` (exists in: ${envsList})` : ''}.`));
|
|
109
114
|
}
|
|
110
115
|
else if (error.response.status === 422) {
|
|
111
|
-
console.error(chalk_1.default.red(
|
|
116
|
+
console.error(chalk_1.default.red((0, api_1.formatValidationError)(error.response.data)));
|
|
112
117
|
}
|
|
113
118
|
else {
|
|
114
119
|
console.error(chalk_1.default.red(`Failed: ${error.response.status}`), error.response.data);
|
|
@@ -124,6 +129,10 @@ async function envSet(keyOrProject, valueOrKey, valueIfProject, options = {}) {
|
|
|
124
129
|
// Global mode: solidactions env set <key> <value>
|
|
125
130
|
const key = keyOrProject;
|
|
126
131
|
const value = valueOrKey;
|
|
132
|
+
if (!(0, env_1.isValidEnvName)(key)) {
|
|
133
|
+
console.error(chalk_1.default.red((0, env_1.envNameError)(key)));
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
127
136
|
if ((0, env_1.isReservedEnvName)(key)) {
|
|
128
137
|
console.error(chalk_1.default.red((0, env_1.reservedEnvNameError)(key)));
|
|
129
138
|
process.exit(1);
|
|
@@ -218,7 +227,7 @@ async function envSet(keyOrProject, valueOrKey, valueIfProject, options = {}) {
|
|
|
218
227
|
console.error(chalk_1.default.red('Authentication failed. Run "solidactions login <api-key>" to re-configure.'));
|
|
219
228
|
}
|
|
220
229
|
else if (error.response.status === 422) {
|
|
221
|
-
console.error(chalk_1.default.red(
|
|
230
|
+
console.error(chalk_1.default.red((0, api_1.formatValidationError)(error.response.data)));
|
|
222
231
|
}
|
|
223
232
|
else {
|
|
224
233
|
console.error(chalk_1.default.red(`Failed: ${error.response.status}`), error.response.data);
|
package/dist/commands/init.js
CHANGED
|
@@ -49,6 +49,22 @@ async function init(directory, options = {}) {
|
|
|
49
49
|
console.error(chalk_1.default.gray('Run in a fresh directory, or use `solidactions ai init` to add AI tooling to an existing project.'));
|
|
50
50
|
process.exit(1);
|
|
51
51
|
}
|
|
52
|
+
// Validate flags BEFORE any network fetch/write — previously this check
|
|
53
|
+
// lived only inside aiInit(), which runs after the template files are
|
|
54
|
+
// already fetched and written.
|
|
55
|
+
if (installSkills && options.claude && options.agents) {
|
|
56
|
+
console.error(chalk_1.default.red('Please specify only one of --claude or --agents'));
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
// Resolve the AI-helper target (CLAUDE.md vs AGENTS.md) UP FRONT, before
|
|
60
|
+
// writing any template file. Previously this decision was made inside
|
|
61
|
+
// aiInit(), AFTER the scaffold was already written — in a non-TTY shell
|
|
62
|
+
// with no --claude/--agents flag, the resulting unanswerable prompt left
|
|
63
|
+
// a half-scaffolded project (no CLAUDE.md/AGENTS.md, no .claude/skills/).
|
|
64
|
+
let aiHelperTarget;
|
|
65
|
+
if (installSkills) {
|
|
66
|
+
aiHelperTarget = await (0, ai_init_1.resolveAiHelperTarget)({ claude: options.claude, agents: options.agents });
|
|
67
|
+
}
|
|
52
68
|
console.log(chalk_1.default.blue(`Scaffolding "${projectName}" in ${targetDir}...`));
|
|
53
69
|
for (const [remoteSuffix, localSuffix] of exports.TEMPLATE_FILES) {
|
|
54
70
|
const remotePath = `${TEMPLATE_PREFIX}/${remoteSuffix}`;
|
|
@@ -62,7 +78,7 @@ async function init(directory, options = {}) {
|
|
|
62
78
|
if (installSkills) {
|
|
63
79
|
console.log('');
|
|
64
80
|
process.chdir(targetDir);
|
|
65
|
-
await (0, ai_init_1.aiInit)({ claude: options.claude, agents: options.agents });
|
|
81
|
+
await (0, ai_init_1.aiInit)({ claude: options.claude, agents: options.agents }, aiHelperTarget);
|
|
66
82
|
}
|
|
67
83
|
console.log('');
|
|
68
84
|
console.log(chalk_1.default.green(`✓ Project "${projectName}" scaffolded.`));
|
|
@@ -71,6 +87,7 @@ async function init(directory, options = {}) {
|
|
|
71
87
|
if (directory) {
|
|
72
88
|
console.log(chalk_1.default.gray(` cd ${directory}`));
|
|
73
89
|
}
|
|
90
|
+
console.log(chalk_1.default.gray(' npm install'));
|
|
74
91
|
console.log(chalk_1.default.gray(` solidactions project deploy ${projectName} -e production`));
|
|
75
92
|
console.log(chalk_1.default.gray(` # If your workflow uses a webhook, retrieve its auto-generated secret`));
|
|
76
93
|
console.log(chalk_1.default.gray(` # and set that value in your sender (e.g. Telegram secret_token):`));
|