@startanaicompany/cli 1.4.19 → 1.4.21
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 +1819 -253
- package/bin/saac.js +11 -0
- package/package.json +1 -1
- package/src/commands/git.js +162 -0
- package/src/commands/logs.js +13 -4
- package/src/lib/api.js +30 -0
package/bin/saac.js
CHANGED
|
@@ -123,6 +123,17 @@ gitCommand
|
|
|
123
123
|
.description('Disconnect a Git account')
|
|
124
124
|
.action(git.disconnect);
|
|
125
125
|
|
|
126
|
+
gitCommand
|
|
127
|
+
.command('repos <git_host>')
|
|
128
|
+
.description('List repositories from a connected Git host')
|
|
129
|
+
.option('-p, --page <number>', 'Page number', '1')
|
|
130
|
+
.option('-n, --per-page <number>', 'Results per page (max: 100)', '20')
|
|
131
|
+
.option('-s, --sort <type>', 'Sort order: updated, created, name', 'updated')
|
|
132
|
+
.option('-v, --visibility <type>', 'Filter: all, public, private', 'all')
|
|
133
|
+
.option('-c, --commits', 'Include latest commit info')
|
|
134
|
+
.option('--json', 'Output as JSON')
|
|
135
|
+
.action(git.repos);
|
|
136
|
+
|
|
126
137
|
// Application management
|
|
127
138
|
program
|
|
128
139
|
.command('init')
|
package/package.json
CHANGED
package/src/commands/git.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
const oauth = require('../lib/oauth');
|
|
6
|
+
const api = require('../lib/api');
|
|
6
7
|
const { isAuthenticated, getUser } = require('../lib/config');
|
|
7
8
|
const logger = require('../lib/logger');
|
|
8
9
|
const { table } = require('table');
|
|
@@ -247,8 +248,169 @@ async function disconnect(host) {
|
|
|
247
248
|
}
|
|
248
249
|
}
|
|
249
250
|
|
|
251
|
+
/**
|
|
252
|
+
* List repositories from a connected Git host
|
|
253
|
+
*/
|
|
254
|
+
async function repos(gitHost, options) {
|
|
255
|
+
try {
|
|
256
|
+
// Check authentication
|
|
257
|
+
if (!isAuthenticated()) {
|
|
258
|
+
logger.error('Not logged in');
|
|
259
|
+
logger.newline();
|
|
260
|
+
logger.info('Run:');
|
|
261
|
+
logger.log(' saac login -e <email> -k <api-key>');
|
|
262
|
+
process.exit(1);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (!gitHost) {
|
|
266
|
+
logger.error('Git host is required');
|
|
267
|
+
logger.newline();
|
|
268
|
+
logger.info('Usage:');
|
|
269
|
+
logger.log(' saac git repos <host>');
|
|
270
|
+
logger.newline();
|
|
271
|
+
logger.info('Examples:');
|
|
272
|
+
logger.log(' saac git repos git.startanaicompany.com');
|
|
273
|
+
logger.log(' saac git repos github.com');
|
|
274
|
+
logger.log(' saac git repos github.com --commits');
|
|
275
|
+
logger.log(' saac git repos github.com --visibility private');
|
|
276
|
+
logger.newline();
|
|
277
|
+
logger.info('To see connected accounts:');
|
|
278
|
+
logger.log(' saac git list');
|
|
279
|
+
process.exit(1);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const spin = logger.spinner(`Fetching repositories from ${gitHost}...`).start();
|
|
283
|
+
|
|
284
|
+
try {
|
|
285
|
+
const result = await api.listGitRepositories(gitHost, {
|
|
286
|
+
page: options.page ? parseInt(options.page, 10) : 1,
|
|
287
|
+
perPage: options.perPage ? parseInt(options.perPage, 10) : 20,
|
|
288
|
+
sort: options.sort || 'updated',
|
|
289
|
+
visibility: options.visibility || 'all',
|
|
290
|
+
includeCommits: options.commits || false,
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
spin.succeed(`Found ${result.count} repositories on ${result.git_host}`);
|
|
294
|
+
|
|
295
|
+
// If JSON output requested, just dump and exit
|
|
296
|
+
if (options.json) {
|
|
297
|
+
console.log(JSON.stringify(result, null, 2));
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (result.count === 0) {
|
|
302
|
+
logger.newline();
|
|
303
|
+
logger.warn('No repositories found');
|
|
304
|
+
logger.newline();
|
|
305
|
+
logger.info('Make sure you have repositories on this Git host');
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
logger.newline();
|
|
310
|
+
logger.section(`Repositories on ${result.git_host} (${result.username})`);
|
|
311
|
+
logger.newline();
|
|
312
|
+
|
|
313
|
+
if (options.commits) {
|
|
314
|
+
// Display with commit info
|
|
315
|
+
const data = [
|
|
316
|
+
['NAME', 'VISIBILITY', 'LAST COMMIT'],
|
|
317
|
+
];
|
|
318
|
+
|
|
319
|
+
result.repositories.forEach((repo) => {
|
|
320
|
+
const visibility = repo.private ? logger.chalk.yellow('private') : logger.chalk.green('public');
|
|
321
|
+
let commitInfo = logger.chalk.dim('No commits');
|
|
322
|
+
|
|
323
|
+
if (repo.latestCommit) {
|
|
324
|
+
const commit = repo.latestCommit;
|
|
325
|
+
const sha = commit.sha.substring(0, 7);
|
|
326
|
+
const message = commit.message.substring(0, 30);
|
|
327
|
+
const date = new Date(commit.date);
|
|
328
|
+
const now = new Date();
|
|
329
|
+
const diffMs = now - date;
|
|
330
|
+
const diffMins = Math.floor(diffMs / 60000);
|
|
331
|
+
const diffHours = Math.floor(diffMs / 3600000);
|
|
332
|
+
const diffDays = Math.floor(diffMs / 86400000);
|
|
333
|
+
|
|
334
|
+
let timeStr;
|
|
335
|
+
if (diffMins < 60) {
|
|
336
|
+
timeStr = `${diffMins}m ago`;
|
|
337
|
+
} else if (diffHours < 24) {
|
|
338
|
+
timeStr = `${diffHours}h ago`;
|
|
339
|
+
} else {
|
|
340
|
+
timeStr = `${diffDays}d ago`;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
commitInfo = `${logger.chalk.dim(sha)} ${message} ${logger.chalk.dim(`(${timeStr})`)}`;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
data.push([
|
|
347
|
+
repo.name,
|
|
348
|
+
visibility,
|
|
349
|
+
commitInfo,
|
|
350
|
+
]);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
console.log(table(data));
|
|
354
|
+
} else {
|
|
355
|
+
// Display without commit info
|
|
356
|
+
const data = [
|
|
357
|
+
['NAME', 'VISIBILITY', 'UPDATED', 'BRANCH', 'LANGUAGE'],
|
|
358
|
+
];
|
|
359
|
+
|
|
360
|
+
result.repositories.forEach((repo) => {
|
|
361
|
+
const visibility = repo.private ? logger.chalk.yellow('private') : logger.chalk.green('public');
|
|
362
|
+
const updated = new Date(repo.updatedAt).toLocaleString();
|
|
363
|
+
const language = repo.language || logger.chalk.dim('N/A');
|
|
364
|
+
|
|
365
|
+
data.push([
|
|
366
|
+
repo.name,
|
|
367
|
+
visibility,
|
|
368
|
+
updated,
|
|
369
|
+
repo.defaultBranch,
|
|
370
|
+
language,
|
|
371
|
+
]);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
console.log(table(data));
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
logger.info(`Showing ${result.count} repositories (page ${result.page})`);
|
|
378
|
+
|
|
379
|
+
logger.newline();
|
|
380
|
+
logger.info('Options:');
|
|
381
|
+
logger.log(' --commits Include latest commit info');
|
|
382
|
+
logger.log(' --visibility <type> Filter: all, public, private');
|
|
383
|
+
logger.log(' --page <number> Page number');
|
|
384
|
+
logger.log(' --per-page <number> Results per page (max: 100)');
|
|
385
|
+
logger.log(' --json Output as JSON');
|
|
386
|
+
|
|
387
|
+
} catch (error) {
|
|
388
|
+
spin.fail('Failed to fetch repositories');
|
|
389
|
+
|
|
390
|
+
if (error.response?.status === 404) {
|
|
391
|
+
logger.newline();
|
|
392
|
+
logger.error(`Not connected to ${gitHost}`);
|
|
393
|
+
logger.newline();
|
|
394
|
+
logger.info('Connect with:');
|
|
395
|
+
logger.log(` saac git connect ${gitHost}`);
|
|
396
|
+
logger.newline();
|
|
397
|
+
logger.info('To see connected accounts:');
|
|
398
|
+
logger.log(' saac git list');
|
|
399
|
+
} else {
|
|
400
|
+
throw error;
|
|
401
|
+
}
|
|
402
|
+
process.exit(1);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
} catch (error) {
|
|
406
|
+
logger.error(error.response?.data?.message || error.message);
|
|
407
|
+
process.exit(1);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
250
411
|
module.exports = {
|
|
251
412
|
connect,
|
|
252
413
|
list,
|
|
253
414
|
disconnect,
|
|
415
|
+
repos,
|
|
254
416
|
};
|
package/src/commands/logs.js
CHANGED
|
@@ -188,11 +188,20 @@ async function getRuntimeLogs(applicationUuid, applicationName, options) {
|
|
|
188
188
|
logger.newline();
|
|
189
189
|
|
|
190
190
|
// Display logs
|
|
191
|
-
if (result.logs
|
|
192
|
-
result.logs
|
|
193
|
-
|
|
194
|
-
|
|
191
|
+
if (result.logs) {
|
|
192
|
+
if (Array.isArray(result.logs)) {
|
|
193
|
+
// Logs is an array
|
|
194
|
+
result.logs.forEach(log => {
|
|
195
|
+
console.log(log);
|
|
196
|
+
});
|
|
197
|
+
} else if (typeof result.logs === 'string') {
|
|
198
|
+
// Logs is a string (most common format from backend)
|
|
199
|
+
console.log(result.logs);
|
|
200
|
+
} else {
|
|
201
|
+
logger.warn('Unexpected log format');
|
|
202
|
+
}
|
|
195
203
|
} else if (typeof result === 'string') {
|
|
204
|
+
// Entire result is a string
|
|
196
205
|
console.log(result);
|
|
197
206
|
} else {
|
|
198
207
|
logger.warn('No logs available');
|
package/src/lib/api.js
CHANGED
|
@@ -290,6 +290,35 @@ async function getExecutionHistory(uuid, params = {}) {
|
|
|
290
290
|
return response.data;
|
|
291
291
|
}
|
|
292
292
|
|
|
293
|
+
/**
|
|
294
|
+
* List repositories from a connected Git host
|
|
295
|
+
* @param {string} gitHost - Git host domain (e.g., 'github.com', 'git.startanaicompany.com')
|
|
296
|
+
* @param {object} options - Query options
|
|
297
|
+
* @param {number} options.page - Page number for pagination (default: 1)
|
|
298
|
+
* @param {number} options.perPage - Results per page (default: 100, max: 100)
|
|
299
|
+
* @param {string} options.sort - Sort order: 'updated', 'created', 'name' (default: 'updated')
|
|
300
|
+
* @param {string} options.visibility - Filter: 'all', 'public', 'private' (default: 'all')
|
|
301
|
+
* @param {boolean} options.includeCommits - Include latest commit info (default: false)
|
|
302
|
+
* @returns {Promise<object>} - Repository listing response
|
|
303
|
+
*/
|
|
304
|
+
async function listGitRepositories(gitHost, options = {}) {
|
|
305
|
+
const client = createClient();
|
|
306
|
+
|
|
307
|
+
// Build query parameters
|
|
308
|
+
const params = {};
|
|
309
|
+
if (options.page) params.page = options.page;
|
|
310
|
+
if (options.perPage) params.per_page = options.perPage;
|
|
311
|
+
if (options.sort) params.sort = options.sort;
|
|
312
|
+
if (options.visibility) params.visibility = options.visibility;
|
|
313
|
+
if (options.includeCommits) params.include_commits = true;
|
|
314
|
+
|
|
315
|
+
// URL encode the git host
|
|
316
|
+
const encodedHost = encodeURIComponent(gitHost);
|
|
317
|
+
|
|
318
|
+
const response = await client.get(`/git/connections/${encodedHost}/repos`, { params });
|
|
319
|
+
return response.data;
|
|
320
|
+
}
|
|
321
|
+
|
|
293
322
|
module.exports = {
|
|
294
323
|
createClient,
|
|
295
324
|
login,
|
|
@@ -315,4 +344,5 @@ module.exports = {
|
|
|
315
344
|
getDeploymentLogs,
|
|
316
345
|
executeCommand,
|
|
317
346
|
getExecutionHistory,
|
|
347
|
+
listGitRepositories,
|
|
318
348
|
};
|