@solidactions/cli 0.6.0 → 0.6.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.
@@ -0,0 +1,215 @@
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.steps = steps;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const init_1 = require("./init");
10
+ async function steps(runId, options) {
11
+ const config = (0, init_1.getConfig)();
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
+ // Flag validation: --follow and --step are incompatible
17
+ if (options.follow && options.step) {
18
+ console.error(chalk_1.default.red('Cannot use --follow with --step.'));
19
+ process.exit(1);
20
+ }
21
+ try {
22
+ const response = await axios_1.default.get(`${config.host}/api/v1/runs/${runId}/steps`, {
23
+ headers: {
24
+ 'Authorization': `Bearer ${config.apiKey}`,
25
+ 'Accept': 'application/json',
26
+ },
27
+ });
28
+ const data = response.data;
29
+ // --json mode: output raw JSON and exit
30
+ if (options.json) {
31
+ if (options.step) {
32
+ const allSteps = flattenSteps(data.workers);
33
+ const found = allSteps.find(s => s.name === options.step);
34
+ if (!found) {
35
+ console.log(JSON.stringify({
36
+ error: 'Step not found',
37
+ available: allSteps.map(s => s.name),
38
+ }, null, 2));
39
+ process.exit(1);
40
+ }
41
+ console.log(JSON.stringify(found, null, 2));
42
+ }
43
+ else {
44
+ console.log(JSON.stringify(data, null, 2));
45
+ }
46
+ return;
47
+ }
48
+ // --step mode: show single step detail
49
+ if (options.step) {
50
+ const allSteps = flattenSteps(data.workers);
51
+ const found = allSteps.find(s => s.name === options.step);
52
+ if (!found) {
53
+ console.error(chalk_1.default.red(`Step "${options.step}" not found.`));
54
+ console.log(chalk_1.default.gray('Available steps:'));
55
+ for (const s of allSteps) {
56
+ console.log(chalk_1.default.gray(` - ${s.name}`));
57
+ }
58
+ process.exit(1);
59
+ }
60
+ displaySingleStep(found);
61
+ return;
62
+ }
63
+ // Default mode: show all steps
64
+ displayAllSteps(runId, data);
65
+ // --follow mode
66
+ if (options.follow) {
67
+ console.log(chalk_1.default.gray('\n--- Following steps (Ctrl+C to stop) ---\n'));
68
+ const pollInterval = setInterval(async () => {
69
+ try {
70
+ const refreshResponse = await axios_1.default.get(`${config.host}/api/v1/runs/${runId}/steps`, {
71
+ headers: {
72
+ 'Authorization': `Bearer ${config.apiKey}`,
73
+ 'Accept': 'application/json',
74
+ },
75
+ });
76
+ const runStatus = await axios_1.default.get(`${config.host}/api/v1/runs/${runId}`, {
77
+ headers: {
78
+ 'Authorization': `Bearer ${config.apiKey}`,
79
+ 'Accept': 'application/json',
80
+ },
81
+ });
82
+ console.clear();
83
+ displayAllSteps(runId, refreshResponse.data);
84
+ if (['completed', 'failed', 'acknowledged'].includes(runStatus.data.status)) {
85
+ clearInterval(pollInterval);
86
+ console.log(chalk_1.default.gray(`\n--- Run ${runStatus.data.status} ---`));
87
+ process.exit(runStatus.data.status === 'completed' ? 0 : 1);
88
+ }
89
+ }
90
+ catch {
91
+ // Ignore transient errors during follow
92
+ }
93
+ }, 2000);
94
+ }
95
+ }
96
+ catch (error) {
97
+ if (error.response) {
98
+ if (error.response.status === 401) {
99
+ console.error(chalk_1.default.red('Authentication failed. Run "solidactions init <api-key>" to re-configure.'));
100
+ }
101
+ else if (error.response.status === 404) {
102
+ console.error(chalk_1.default.red('Run not found.'));
103
+ }
104
+ else {
105
+ console.error(chalk_1.default.red(`Failed: ${error.response.status}`), error.response.data);
106
+ }
107
+ }
108
+ else {
109
+ console.error(chalk_1.default.red('Connection failed:'), error.message);
110
+ }
111
+ process.exit(1);
112
+ }
113
+ }
114
+ function flattenSteps(workers) {
115
+ const allSteps = [];
116
+ for (const worker of workers) {
117
+ for (const step of worker.steps || []) {
118
+ allSteps.push(step);
119
+ }
120
+ }
121
+ return allSteps;
122
+ }
123
+ function displaySingleStep(step) {
124
+ const statusColor = getStatusColor(step.status);
125
+ console.log(chalk_1.default.blue(`Step: ${step.name}`));
126
+ console.log(` Status: ${statusColor(step.status)}`);
127
+ console.log(` Type: ${step.type}`);
128
+ console.log(` Duration: ${formatDuration(step.duration_ms)}`);
129
+ console.log(` Started: ${step.started_at || '-'}`);
130
+ console.log(` Completed: ${step.completed_at || '-'}`);
131
+ if (step.output !== null && step.output !== undefined) {
132
+ console.log(` Output:`);
133
+ console.log(JSON.stringify(step.output, null, 2));
134
+ }
135
+ else {
136
+ console.log(` Output: ${chalk_1.default.gray('(no output)')}`);
137
+ }
138
+ if (step.error) {
139
+ console.log(chalk_1.default.red(` Error:`));
140
+ console.log(chalk_1.default.red(JSON.stringify(step.error, null, 2)));
141
+ }
142
+ }
143
+ function displayAllSteps(runId, data) {
144
+ const workers = data.workers || [];
145
+ const signalWaits = data.signal_waits || [];
146
+ console.log(chalk_1.default.blue(`Steps for run: ${runId}`));
147
+ console.log('');
148
+ for (let i = 0; i < workers.length; i++) {
149
+ const worker = workers[i];
150
+ const workerStatus = getStatusColor(worker.status || 'unknown');
151
+ const workerDuration = calculateDuration(worker.started_at, worker.completed_at);
152
+ console.log(chalk_1.default.white.bold(`Worker ${i + 1}`) + ' ' + workerStatus(worker.status || 'unknown') + chalk_1.default.gray(` (${workerDuration})`));
153
+ for (const step of worker.steps || []) {
154
+ const statusColor = getStatusColor(step.status);
155
+ const name = (step.name || '?').padEnd(30);
156
+ const status = statusColor((step.status || '?').padEnd(10));
157
+ const type = (step.type || '?').padEnd(10);
158
+ const duration = formatDuration(step.duration_ms);
159
+ console.log(` ${name} ${status} ${type} ${chalk_1.default.gray(duration)}`);
160
+ if (step.output !== null && step.output !== undefined) {
161
+ const outputStr = JSON.stringify(step.output, null, 2);
162
+ for (const line of outputStr.split('\n')) {
163
+ console.log(chalk_1.default.gray(` ${line}`));
164
+ }
165
+ }
166
+ else {
167
+ console.log(chalk_1.default.gray(' (no output)'));
168
+ }
169
+ if (step.error) {
170
+ console.log(chalk_1.default.red(` Error: ${JSON.stringify(step.error, null, 2)}`));
171
+ }
172
+ }
173
+ // Show signal waits between workers
174
+ if (i < workers.length - 1) {
175
+ const wait = signalWaits[i];
176
+ if (wait) {
177
+ console.log(chalk_1.default.yellow(` ⏳ ${wait.signal_name} (${formatDuration(wait.duration_ms)})`));
178
+ }
179
+ }
180
+ console.log('');
181
+ }
182
+ }
183
+ function formatDuration(ms) {
184
+ if (ms === null || ms === undefined)
185
+ return '-';
186
+ if (ms < 1000)
187
+ return `${ms}ms`;
188
+ if (ms < 60000)
189
+ return `${Math.round(ms / 1000)}s`;
190
+ if (ms < 3600000)
191
+ return `${Math.round(ms / 60000)}m`;
192
+ return `${Math.round(ms / 3600000)}h`;
193
+ }
194
+ function calculateDuration(startedAt, completedAt) {
195
+ if (!startedAt)
196
+ return '-';
197
+ const start = new Date(startedAt).getTime();
198
+ const end = completedAt ? new Date(completedAt).getTime() : Date.now();
199
+ return formatDuration(end - start);
200
+ }
201
+ function getStatusColor(status) {
202
+ switch (status.toLowerCase()) {
203
+ case 'completed':
204
+ return chalk_1.default.green;
205
+ case 'running':
206
+ return chalk_1.default.blue;
207
+ case 'pending':
208
+ case 'queued':
209
+ return chalk_1.default.yellow;
210
+ case 'failed':
211
+ return chalk_1.default.red;
212
+ default:
213
+ return chalk_1.default.gray;
214
+ }
215
+ }
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ const deploy_1 = require("./commands/deploy");
6
6
  const init_1 = require("./commands/init");
7
7
  const logs_1 = require("./commands/logs");
8
8
  const logs_build_1 = require("./commands/logs-build");
9
+ const steps_1 = require("./commands/steps");
9
10
  const run_1 = require("./commands/run");
10
11
  const runs_1 = require("./commands/runs");
11
12
  const pull_1 = require("./commands/pull");
@@ -122,6 +123,16 @@ program
122
123
  .action((project) => {
123
124
  (0, logs_build_1.logsBuild)(project);
124
125
  });
126
+ program
127
+ .command('steps')
128
+ .description('View step outputs and timing for a workflow run')
129
+ .argument('<run-id>', 'Run ID')
130
+ .option('-s, --step <name>', 'Show output for a specific step')
131
+ .option('--json', 'Output as JSON (for piping/redirection)')
132
+ .option('-f, --follow', 'Follow step progress for in-progress runs')
133
+ .action((runId, options) => {
134
+ (0, steps_1.steps)(runId, options);
135
+ });
125
136
  // =============================================================================
126
137
  // Environment Variables
127
138
  // =============================================================================
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidactions/cli",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "SolidActions CLI - Deploy and manage workflow automation",
5
5
  "main": "dist/index.js",
6
6
  "bin": {