@solidactions/cli 0.7.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -25
- package/dist/commands/ai-examples.js +1 -1
- package/dist/commands/deploy.js +26 -27
- package/dist/commands/env-delete.js +6 -22
- package/dist/commands/env-list.js +4 -14
- package/dist/commands/env-map.js +29 -17
- package/dist/commands/env-pull.js +6 -16
- package/dist/commands/env-push.js +5 -16
- package/dist/commands/env-set.js +41 -27
- package/dist/commands/init.js +21 -5
- package/dist/commands/project-list.js +52 -0
- package/dist/commands/{logs-build.js → project-logs.js} +3 -10
- package/dist/commands/pull.js +32 -22
- package/dist/commands/run-list.js +186 -0
- package/dist/commands/{run.js → run-start.js} +4 -15
- package/dist/commands/run-view.js +255 -0
- package/dist/commands/schedule-delete.js +4 -14
- package/dist/commands/schedule-list.js +3 -10
- package/dist/commands/schedule-set.js +48 -12
- package/dist/commands/{webhooks.js → webhook-list.js} +7 -14
- package/dist/commands/workspaces.js +89 -0
- package/dist/index.js +130 -98
- package/dist/utils/api.js +129 -0
- package/package.json +4 -4
- package/dist/commands/logs.js +0 -119
- package/dist/commands/runs.js +0 -97
- package/dist/commands/steps.js +0 -215
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.runView = runView;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const api_1 = require("../utils/api");
|
|
10
|
+
async function runView(runId, options) {
|
|
11
|
+
const config = await (0, api_1.requireConfigWithWorkspace)();
|
|
12
|
+
try {
|
|
13
|
+
// Fetch run data (includes session timing)
|
|
14
|
+
const runResponse = await axios_1.default.get(`${config.host}/api/v1/runs/${runId}`, {
|
|
15
|
+
headers: (0, api_1.getApiHeaders)(config),
|
|
16
|
+
});
|
|
17
|
+
const runData = runResponse.data;
|
|
18
|
+
// Build timeline
|
|
19
|
+
const triggeredAt = runData.triggered_at || runData.created_at;
|
|
20
|
+
const sessionStartedMs = runData.session_started_at_epoch_ms;
|
|
21
|
+
const sessionCompletedMs = runData.session_completed_at_epoch_ms;
|
|
22
|
+
const triggeredMs = triggeredAt ? new Date(triggeredAt).getTime() : null;
|
|
23
|
+
const totalMs = (triggeredMs && sessionCompletedMs) ? sessionCompletedMs - triggeredMs : null;
|
|
24
|
+
const timeline = {
|
|
25
|
+
triggered: triggeredAt || null,
|
|
26
|
+
started: sessionStartedMs ? new Date(sessionStartedMs).toISOString() : null,
|
|
27
|
+
completed: sessionCompletedMs ? new Date(sessionCompletedMs).toISOString() : null,
|
|
28
|
+
totalMs,
|
|
29
|
+
};
|
|
30
|
+
// --logs: fetch and display raw logs
|
|
31
|
+
if (options.logs) {
|
|
32
|
+
const logsResponse = await axios_1.default.get(`${config.host}/api/v1/runs/${runId}/logs`, {
|
|
33
|
+
headers: (0, api_1.getApiHeaders)(config),
|
|
34
|
+
});
|
|
35
|
+
const logData = logsResponse.data.logs || '';
|
|
36
|
+
// --logs always outputs raw text, even with --json (wrapping logs in JSON is pointless)
|
|
37
|
+
if (typeof logData === 'string') {
|
|
38
|
+
console.log(logData);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
console.log(JSON.stringify(logData, null, 2));
|
|
42
|
+
}
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// Fetch steps data
|
|
46
|
+
const stepsResponse = await axios_1.default.get(`${config.host}/api/v1/runs/${runId}/steps`, {
|
|
47
|
+
headers: (0, api_1.getApiHeaders)(config),
|
|
48
|
+
});
|
|
49
|
+
const stepsData = stepsResponse.data;
|
|
50
|
+
const flatSteps = flattenSteps(stepsData.workers || []);
|
|
51
|
+
// --timeline
|
|
52
|
+
if (options.timeline) {
|
|
53
|
+
if (options.json) {
|
|
54
|
+
console.log(JSON.stringify(timeline, null, 2));
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
displayTimeline(runData, timeline);
|
|
58
|
+
}
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
// --steps
|
|
62
|
+
if (options.steps) {
|
|
63
|
+
if (options.json) {
|
|
64
|
+
console.log(JSON.stringify(flatSteps, null, 2));
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
displayStepsTable(flatSteps);
|
|
68
|
+
}
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
// Full view
|
|
72
|
+
// Fetch logs for the full view
|
|
73
|
+
const logsResponse = await axios_1.default.get(`${config.host}/api/v1/runs/${runId}/logs`, {
|
|
74
|
+
headers: (0, api_1.getApiHeaders)(config),
|
|
75
|
+
});
|
|
76
|
+
if (options.json) {
|
|
77
|
+
// Full JSON output
|
|
78
|
+
const output = {
|
|
79
|
+
id: runData.id,
|
|
80
|
+
workflow: runData.workflow_name,
|
|
81
|
+
project: runData.project_name,
|
|
82
|
+
status: runData.execution_status || runData.status,
|
|
83
|
+
exitCode: runData.exit_code ?? null,
|
|
84
|
+
timeline,
|
|
85
|
+
steps: flatSteps,
|
|
86
|
+
logs: logsResponse.data.logs || '',
|
|
87
|
+
};
|
|
88
|
+
if (runData.output)
|
|
89
|
+
output.output = runData.output;
|
|
90
|
+
if (runData.error)
|
|
91
|
+
output.error = runData.error;
|
|
92
|
+
console.log(JSON.stringify(output, null, 2));
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
// Human-readable output
|
|
96
|
+
displayFullView(runData, timeline, flatSteps, logsResponse.data);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
if (error.response) {
|
|
101
|
+
if (error.response.status === 401) {
|
|
102
|
+
console.error(chalk_1.default.red('Authentication failed. Run "solidactions init <api-key>" to re-configure.'));
|
|
103
|
+
}
|
|
104
|
+
else if (error.response.status === 404) {
|
|
105
|
+
console.error(chalk_1.default.red('Run not found.'));
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
console.error(chalk_1.default.red(`Failed: ${error.response.status}`), error.response.data);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
console.error(chalk_1.default.red('Connection failed:'), error.message);
|
|
113
|
+
}
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// ─── Display helpers ───────────────────────────────────────────────────────
|
|
118
|
+
function displayFullView(runData, timeline, steps, logsData) {
|
|
119
|
+
const status = runData.execution_status || runData.status;
|
|
120
|
+
const exitCode = runData.exit_code;
|
|
121
|
+
const statusColor = getStatusColor(status);
|
|
122
|
+
console.log('');
|
|
123
|
+
console.log(chalk_1.default.bold(`Run #${runData.id}`) + chalk_1.default.gray(` — ${runData.workflow_name} (${runData.project_name})`));
|
|
124
|
+
console.log('');
|
|
125
|
+
// Status line
|
|
126
|
+
const exitStr = exitCode !== null && exitCode !== undefined ? ` (exit ${exitCode})` : '';
|
|
127
|
+
console.log(` Status: ${statusColor(status)}${chalk_1.default.gray(exitStr)}`);
|
|
128
|
+
console.log(` Trigger: ${chalk_1.default.gray(runData.triggered_by || '-')}`);
|
|
129
|
+
// Timeline
|
|
130
|
+
displayTimeline(runData, timeline);
|
|
131
|
+
// Steps
|
|
132
|
+
if (steps.length > 0) {
|
|
133
|
+
console.log('');
|
|
134
|
+
console.log(chalk_1.default.bold(' Steps:'));
|
|
135
|
+
displayStepsTable(steps, ' ');
|
|
136
|
+
}
|
|
137
|
+
// Output
|
|
138
|
+
if (runData.output) {
|
|
139
|
+
console.log('');
|
|
140
|
+
console.log(chalk_1.default.bold(' Output:'));
|
|
141
|
+
const outputStr = JSON.stringify(unwrapOutput(runData.output), null, 2);
|
|
142
|
+
for (const line of outputStr.split('\n')) {
|
|
143
|
+
console.log(chalk_1.default.gray(` ${line}`));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// Error
|
|
147
|
+
if (runData.error) {
|
|
148
|
+
console.log('');
|
|
149
|
+
console.log(chalk_1.default.bold.red(' Error:'));
|
|
150
|
+
console.log(chalk_1.default.red(` ${runData.error}`));
|
|
151
|
+
}
|
|
152
|
+
// Logs snippet
|
|
153
|
+
const logs = logsData.logs || '';
|
|
154
|
+
if (logs && typeof logs === 'string' && logs.trim()) {
|
|
155
|
+
const logLines = logs.trim().split('\n');
|
|
156
|
+
const showLines = logLines.length > 10 ? logLines.slice(-10) : logLines;
|
|
157
|
+
console.log('');
|
|
158
|
+
console.log(chalk_1.default.bold(' Logs:') + chalk_1.default.gray(logLines.length > 10 ? ` (last 10 of ${logLines.length} lines, use --logs for full)` : ''));
|
|
159
|
+
for (const line of showLines) {
|
|
160
|
+
console.log(chalk_1.default.gray(` ${line}`));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// Errors from workers
|
|
164
|
+
const errors = logsData.errors || [];
|
|
165
|
+
if (errors.length > 0) {
|
|
166
|
+
console.log('');
|
|
167
|
+
for (const err of errors) {
|
|
168
|
+
console.log(chalk_1.default.red(` Worker ${err.worker}: ${err.error}`));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
console.log('');
|
|
172
|
+
}
|
|
173
|
+
function displayTimeline(runData, timeline) {
|
|
174
|
+
const formatTs = (iso) => {
|
|
175
|
+
if (!iso)
|
|
176
|
+
return '-';
|
|
177
|
+
const d = new Date(iso);
|
|
178
|
+
return d.toLocaleString();
|
|
179
|
+
};
|
|
180
|
+
console.log(` Triggered: ${chalk_1.default.gray(formatTs(timeline.triggered))}`);
|
|
181
|
+
console.log(` Started: ${chalk_1.default.gray(formatTs(timeline.started))}`);
|
|
182
|
+
console.log(` Completed: ${chalk_1.default.gray(formatTs(timeline.completed))}`);
|
|
183
|
+
console.log(` Duration: ${chalk_1.default.gray(timeline.totalMs ? formatDuration(timeline.totalMs) : '-')}`);
|
|
184
|
+
}
|
|
185
|
+
function displayStepsTable(steps, indent = ' ') {
|
|
186
|
+
if (steps.length === 0) {
|
|
187
|
+
console.log(chalk_1.default.gray(`${indent}(no steps)`));
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
console.log(chalk_1.default.gray(`${indent}${'STEP'.padEnd(24)}${'STATUS'.padEnd(12)}${'DURATION'.padEnd(12)}OUTPUT`));
|
|
191
|
+
console.log(chalk_1.default.gray(`${indent}${'─'.repeat(72)}`));
|
|
192
|
+
for (const step of steps) {
|
|
193
|
+
const name = (step.name || '?').padEnd(24);
|
|
194
|
+
const status = step.completedAt ? 'completed' : step.startedAt ? 'running' : 'pending';
|
|
195
|
+
const statusColor = getStatusColor(status);
|
|
196
|
+
const duration = formatDuration(step.durationMs);
|
|
197
|
+
const output = step.output ? truncate(JSON.stringify(unwrapOutput(step.output)), 40) : '-';
|
|
198
|
+
console.log(`${indent}${name}${statusColor(status.padEnd(12))}${chalk_1.default.gray(duration.padEnd(12))}${chalk_1.default.gray(output)}`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// ─── Utility ───────────────────────────────────────────────────────────────
|
|
202
|
+
function flattenSteps(workers) {
|
|
203
|
+
const steps = [];
|
|
204
|
+
for (const worker of workers) {
|
|
205
|
+
for (const step of worker.steps || []) {
|
|
206
|
+
steps.push({
|
|
207
|
+
name: step.name,
|
|
208
|
+
startedAt: step.started_at || null,
|
|
209
|
+
completedAt: step.completed_at || null,
|
|
210
|
+
durationMs: step.duration_ms ?? null,
|
|
211
|
+
output: step.output ?? null,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return steps;
|
|
216
|
+
}
|
|
217
|
+
function unwrapOutput(output) {
|
|
218
|
+
if (output && output.__solidactions_serializer === 'superjson' && output.json) {
|
|
219
|
+
return output.json;
|
|
220
|
+
}
|
|
221
|
+
return output;
|
|
222
|
+
}
|
|
223
|
+
function formatDuration(ms) {
|
|
224
|
+
if (ms === null || ms === undefined)
|
|
225
|
+
return '-';
|
|
226
|
+
if (ms < 1000)
|
|
227
|
+
return `${ms}ms`;
|
|
228
|
+
if (ms < 60000)
|
|
229
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
230
|
+
if (ms < 3600000)
|
|
231
|
+
return `${Math.round(ms / 60000)}m`;
|
|
232
|
+
return `${Math.round(ms / 3600000)}h`;
|
|
233
|
+
}
|
|
234
|
+
function truncate(str, max) {
|
|
235
|
+
if (str.length <= max)
|
|
236
|
+
return str;
|
|
237
|
+
return str.substring(0, max - 3) + '...';
|
|
238
|
+
}
|
|
239
|
+
function getStatusColor(status) {
|
|
240
|
+
switch (status?.toLowerCase()) {
|
|
241
|
+
case 'completed':
|
|
242
|
+
case 'success':
|
|
243
|
+
return chalk_1.default.green;
|
|
244
|
+
case 'running':
|
|
245
|
+
return chalk_1.default.blue;
|
|
246
|
+
case 'pending':
|
|
247
|
+
case 'queued':
|
|
248
|
+
return chalk_1.default.yellow;
|
|
249
|
+
case 'failed':
|
|
250
|
+
case 'error':
|
|
251
|
+
return chalk_1.default.red;
|
|
252
|
+
default:
|
|
253
|
+
return chalk_1.default.gray;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
@@ -7,21 +7,14 @@ exports.scheduleDelete = scheduleDelete;
|
|
|
7
7
|
const axios_1 = __importDefault(require("axios"));
|
|
8
8
|
const chalk_1 = __importDefault(require("chalk"));
|
|
9
9
|
const prompts_1 = __importDefault(require("prompts"));
|
|
10
|
-
const
|
|
10
|
+
const api_1 = require("../utils/api");
|
|
11
11
|
async function scheduleDelete(projectName, scheduleId, options = {}) {
|
|
12
|
-
const config = (0,
|
|
13
|
-
if (!config?.apiKey) {
|
|
14
|
-
console.error(chalk_1.default.red('Not initialized. Run "solidactions init <api-key>" first.'));
|
|
15
|
-
process.exit(1);
|
|
16
|
-
}
|
|
12
|
+
const config = await (0, api_1.requireConfigWithWorkspace)();
|
|
17
13
|
console.log(chalk_1.default.blue(`Deleting schedule ${scheduleId} from project "${projectName}"...`));
|
|
18
14
|
try {
|
|
19
15
|
// First, get the schedule details for confirmation
|
|
20
16
|
const listResponse = await axios_1.default.get(`${config.host}/api/v1/projects/${projectName}/schedules`, {
|
|
21
|
-
headers:
|
|
22
|
-
'Authorization': `Bearer ${config.apiKey}`,
|
|
23
|
-
'Accept': 'application/json',
|
|
24
|
-
},
|
|
17
|
+
headers: (0, api_1.getApiHeaders)(config),
|
|
25
18
|
});
|
|
26
19
|
const schedules = listResponse.data || [];
|
|
27
20
|
const schedule = schedules.find((s) => s.id?.toString() === scheduleId);
|
|
@@ -44,10 +37,7 @@ async function scheduleDelete(projectName, scheduleId, options = {}) {
|
|
|
44
37
|
}
|
|
45
38
|
// Delete the schedule
|
|
46
39
|
await axios_1.default.delete(`${config.host}/api/v1/projects/${projectName}/schedules/${scheduleId}`, {
|
|
47
|
-
headers:
|
|
48
|
-
'Authorization': `Bearer ${config.apiKey}`,
|
|
49
|
-
'Accept': 'application/json',
|
|
50
|
-
},
|
|
40
|
+
headers: (0, api_1.getApiHeaders)(config),
|
|
51
41
|
});
|
|
52
42
|
console.log(chalk_1.default.green(`Schedule ${scheduleId} deleted successfully.`));
|
|
53
43
|
console.log(chalk_1.default.gray(` Workflow: ${schedule.workflow_name || schedule.workflow_slug}`));
|
|
@@ -6,20 +6,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.scheduleList = scheduleList;
|
|
7
7
|
const axios_1 = __importDefault(require("axios"));
|
|
8
8
|
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
-
const
|
|
9
|
+
const api_1 = require("../utils/api");
|
|
10
10
|
async function scheduleList(projectName) {
|
|
11
|
-
const config = (0,
|
|
12
|
-
if (!config?.apiKey) {
|
|
13
|
-
console.error(chalk_1.default.red('Not initialized. Run "solidactions init <api-key>" first.'));
|
|
14
|
-
process.exit(1);
|
|
15
|
-
}
|
|
11
|
+
const config = await (0, api_1.requireConfigWithWorkspace)();
|
|
16
12
|
console.log(chalk_1.default.blue(`Schedules for project "${projectName}":`));
|
|
17
13
|
try {
|
|
18
14
|
const response = await axios_1.default.get(`${config.host}/api/v1/projects/${projectName}/schedules`, {
|
|
19
|
-
headers:
|
|
20
|
-
'Authorization': `Bearer ${config.apiKey}`,
|
|
21
|
-
'Accept': 'application/json',
|
|
22
|
-
},
|
|
15
|
+
headers: (0, api_1.getApiHeaders)(config),
|
|
23
16
|
});
|
|
24
17
|
const schedules = response.data || [];
|
|
25
18
|
if (schedules.length === 0) {
|
|
@@ -6,14 +6,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.scheduleSet = scheduleSet;
|
|
7
7
|
const axios_1 = __importDefault(require("axios"));
|
|
8
8
|
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
-
const
|
|
9
|
+
const prompts_1 = __importDefault(require("prompts"));
|
|
10
|
+
const api_1 = require("../utils/api");
|
|
10
11
|
async function scheduleSet(projectName, cron, options) {
|
|
11
|
-
const config = (0,
|
|
12
|
-
if (!config?.apiKey) {
|
|
13
|
-
console.error(chalk_1.default.red('Not initialized. Run "solidactions init <api-key>" first.'));
|
|
14
|
-
process.exit(1);
|
|
15
|
-
}
|
|
16
|
-
console.log(chalk_1.default.blue(`Setting schedule for project "${projectName}"...`));
|
|
12
|
+
const config = await (0, api_1.requireConfigWithWorkspace)();
|
|
17
13
|
// Parse input JSON if provided
|
|
18
14
|
let inputData;
|
|
19
15
|
if (options.input) {
|
|
@@ -25,6 +21,50 @@ async function scheduleSet(projectName, cron, options) {
|
|
|
25
21
|
process.exit(1);
|
|
26
22
|
}
|
|
27
23
|
}
|
|
24
|
+
// Check for existing schedule on the same workflow
|
|
25
|
+
if (!options.yes) {
|
|
26
|
+
try {
|
|
27
|
+
const listResponse = await axios_1.default.get(`${config.host}/api/v1/projects/${projectName}/schedules`, {
|
|
28
|
+
headers: (0, api_1.getApiHeaders)(config),
|
|
29
|
+
});
|
|
30
|
+
const schedules = listResponse.data.data || listResponse.data || [];
|
|
31
|
+
const existing = schedules.find((s) => {
|
|
32
|
+
if (options.workflow) {
|
|
33
|
+
return s.workflow_name === options.workflow || s.workflow_slug === options.workflow;
|
|
34
|
+
}
|
|
35
|
+
return true; // No workflow specified — any existing schedule is a match
|
|
36
|
+
});
|
|
37
|
+
if (existing) {
|
|
38
|
+
const workflowName = existing.workflow_name || existing.workflow_slug || 'unknown';
|
|
39
|
+
console.log(chalk_1.default.yellow(`"${workflowName}" already has a schedule: ${existing.cron_expression}`));
|
|
40
|
+
const confirm = await (0, prompts_1.default)({
|
|
41
|
+
type: 'select',
|
|
42
|
+
name: 'action',
|
|
43
|
+
message: 'What would you like to do?',
|
|
44
|
+
choices: [
|
|
45
|
+
{ title: 'Replace existing schedule', value: 'replace' },
|
|
46
|
+
{ title: 'Add another schedule', value: 'add' },
|
|
47
|
+
{ title: 'Cancel', value: 'cancel' },
|
|
48
|
+
],
|
|
49
|
+
});
|
|
50
|
+
if (confirm.action === 'cancel' || confirm.action === undefined) {
|
|
51
|
+
console.log(chalk_1.default.gray('Cancelled.'));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (confirm.action === 'replace') {
|
|
55
|
+
// Delete the existing schedule first
|
|
56
|
+
await axios_1.default.delete(`${config.host}/api/v1/projects/${projectName}/schedules/${existing.id}`, {
|
|
57
|
+
headers: (0, api_1.getApiHeaders)(config),
|
|
58
|
+
});
|
|
59
|
+
console.log(chalk_1.default.gray(`Removed old schedule (${existing.cron_expression}).`));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// If we can't check, proceed anyway
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
console.log(chalk_1.default.blue(`Setting schedule for project "${projectName}"...`));
|
|
28
68
|
try {
|
|
29
69
|
const payload = {
|
|
30
70
|
cron,
|
|
@@ -36,11 +76,7 @@ async function scheduleSet(projectName, cron, options) {
|
|
|
36
76
|
payload.input = inputData;
|
|
37
77
|
}
|
|
38
78
|
await axios_1.default.post(`${config.host}/api/v1/projects/${projectName}/schedules`, payload, {
|
|
39
|
-
headers:
|
|
40
|
-
'Authorization': `Bearer ${config.apiKey}`,
|
|
41
|
-
'Accept': 'application/json',
|
|
42
|
-
'Content-Type': 'application/json',
|
|
43
|
-
},
|
|
79
|
+
headers: (0, api_1.getApiHeaders)(config, 'application/json'),
|
|
44
80
|
});
|
|
45
81
|
console.log(chalk_1.default.green(`Schedule set successfully!`));
|
|
46
82
|
console.log(chalk_1.default.gray(` Cron: ${cron}`));
|
|
@@ -6,13 +6,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.webhookList = webhookList;
|
|
7
7
|
const axios_1 = __importDefault(require("axios"));
|
|
8
8
|
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
-
const
|
|
9
|
+
const api_1 = require("../utils/api");
|
|
10
10
|
async function webhookList(projectName, options = {}) {
|
|
11
|
-
const config = (0,
|
|
12
|
-
if (!config?.apiKey) {
|
|
13
|
-
console.error(chalk_1.default.red('Not initialized. Run "solidactions init <api-key>" first.'));
|
|
14
|
-
process.exit(1);
|
|
15
|
-
}
|
|
11
|
+
const config = await (0, api_1.requireConfigWithWorkspace)();
|
|
16
12
|
const environment = options.env || 'dev';
|
|
17
13
|
const projectSlug = environment === 'production' ? projectName : `${projectName}-${environment}`;
|
|
18
14
|
console.log(chalk_1.default.blue(`Webhooks for project "${projectName}"${environment !== 'production' ? ` (${environment})` : ''}:`));
|
|
@@ -22,13 +18,10 @@ async function webhookList(projectName, options = {}) {
|
|
|
22
18
|
params.show_secrets = 'true';
|
|
23
19
|
}
|
|
24
20
|
const response = await axios_1.default.get(`${config.host}/api/v1/projects/${projectSlug}/webhooks`, {
|
|
25
|
-
headers:
|
|
26
|
-
'Authorization': `Bearer ${config.apiKey}`,
|
|
27
|
-
'Accept': 'application/json',
|
|
28
|
-
},
|
|
21
|
+
headers: (0, api_1.getApiHeaders)(config),
|
|
29
22
|
params,
|
|
30
23
|
});
|
|
31
|
-
const webhooks = response.data || [];
|
|
24
|
+
const webhooks = response.data.data || [];
|
|
32
25
|
if (webhooks.length === 0) {
|
|
33
26
|
console.log(chalk_1.default.yellow('No webhooks found for project "' + projectName + '".'));
|
|
34
27
|
return;
|
|
@@ -43,11 +36,11 @@ async function webhookList(projectName, options = {}) {
|
|
|
43
36
|
console.log(chalk_1.default.gray('-'.repeat(90)));
|
|
44
37
|
}
|
|
45
38
|
for (const webhook of webhooks) {
|
|
46
|
-
const name = webhook.
|
|
47
|
-
const url = webhook.
|
|
39
|
+
const name = webhook.workflow_name || webhook.workflow_slug || '?';
|
|
40
|
+
const url = webhook.webhook_path_url || webhook.webhook_url || '?';
|
|
48
41
|
let line = name.padEnd(30) + chalk_1.default.cyan(url.padEnd(60));
|
|
49
42
|
if (options.showSecrets) {
|
|
50
|
-
const secret = webhook.
|
|
43
|
+
const secret = webhook.webhook_secret || '-';
|
|
51
44
|
line += chalk_1.default.gray(secret);
|
|
52
45
|
}
|
|
53
46
|
console.log(line);
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.workspacesList = workspacesList;
|
|
7
|
+
exports.workspaceSet = workspaceSet;
|
|
8
|
+
const axios_1 = __importDefault(require("axios"));
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const api_1 = require("../utils/api");
|
|
11
|
+
const init_1 = require("./init");
|
|
12
|
+
async function workspacesList() {
|
|
13
|
+
const config = (0, api_1.requireConfig)();
|
|
14
|
+
try {
|
|
15
|
+
const response = await axios_1.default.get(`${config.host}/api/v1/workspaces`, {
|
|
16
|
+
headers: {
|
|
17
|
+
'Authorization': `Bearer ${config.apiKey}`,
|
|
18
|
+
'Accept': 'application/json',
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
// API returns { workspaces: { "Org Name": [{ id, name, role, tenant_name, ... }] } }
|
|
22
|
+
const grouped = response.data.workspaces || response.data.data || response.data;
|
|
23
|
+
let hasWorkspaces = false;
|
|
24
|
+
console.log(chalk_1.default.blue(`\nYour workspaces:\n`));
|
|
25
|
+
if (typeof grouped === 'object' && !Array.isArray(grouped)) {
|
|
26
|
+
for (const orgName of Object.keys(grouped)) {
|
|
27
|
+
console.log(` ${chalk_1.default.white(orgName)}`);
|
|
28
|
+
for (const ws of grouped[orgName]) {
|
|
29
|
+
hasWorkspaces = true;
|
|
30
|
+
const current = config.workspaceId === ws.id ? chalk_1.default.green(' ← current') : '';
|
|
31
|
+
console.log(` ${chalk_1.default.white(ws.name)} ${chalk_1.default.gray(`(${ws.role})`)}${current}`);
|
|
32
|
+
console.log(chalk_1.default.gray(` ID: ${ws.id}`));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
else if (Array.isArray(grouped)) {
|
|
37
|
+
for (const ws of grouped) {
|
|
38
|
+
hasWorkspaces = true;
|
|
39
|
+
const current = config.workspaceId === ws.id ? chalk_1.default.green(' ← current') : '';
|
|
40
|
+
console.log(` ${chalk_1.default.white(ws.name)} ${chalk_1.default.gray(`(${ws.org_name || ''}, ${ws.role})`)}${current}`);
|
|
41
|
+
console.log(chalk_1.default.gray(` ID: ${ws.id}`));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (!hasWorkspaces) {
|
|
45
|
+
console.log(chalk_1.default.yellow('No workspaces found.'));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
console.log('');
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
console.error(chalk_1.default.red('Failed to list workspaces:'), error.response?.data?.message || error.message);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async function workspaceSet(workspaceId) {
|
|
56
|
+
const config = (0, api_1.requireConfig)();
|
|
57
|
+
// Validate the workspace exists and user has access
|
|
58
|
+
try {
|
|
59
|
+
const response = await axios_1.default.get(`${config.host}/api/v1/workspaces`, {
|
|
60
|
+
headers: {
|
|
61
|
+
'Authorization': `Bearer ${config.apiKey}`,
|
|
62
|
+
'Accept': 'application/json',
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
// Flatten grouped response
|
|
66
|
+
const grouped = response.data.workspaces || response.data.data || response.data;
|
|
67
|
+
let allWorkspaces = [];
|
|
68
|
+
if (typeof grouped === 'object' && !Array.isArray(grouped)) {
|
|
69
|
+
for (const orgWorkspaces of Object.values(grouped)) {
|
|
70
|
+
allWorkspaces.push(...orgWorkspaces);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else if (Array.isArray(grouped)) {
|
|
74
|
+
allWorkspaces = grouped;
|
|
75
|
+
}
|
|
76
|
+
const workspace = allWorkspaces.find((w) => w.id === workspaceId || w.slug === workspaceId || w.name === workspaceId);
|
|
77
|
+
if (!workspace) {
|
|
78
|
+
console.error(chalk_1.default.red(`Workspace "${workspaceId}" not found. Run \`solidactions workspace list\` to list available workspaces.`));
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
config.workspaceId = workspace.id;
|
|
82
|
+
(0, init_1.saveConfig)(config);
|
|
83
|
+
console.log(chalk_1.default.green(`Workspace set to: ${workspace.name} (${workspace.id})`));
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
console.error(chalk_1.default.red('Failed to set workspace:'), error.response?.data?.message || error.message);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
}
|