@orchagent/cli 0.3.58 → 0.3.60
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/github.js +116 -285
- package/dist/commands/init.js +1 -1
- package/dist/commands/pull.js +61 -2
- package/dist/commands/service.js +3 -3
- package/package.json +1 -1
package/dist/commands/github.js
CHANGED
|
@@ -37,7 +37,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.registerGitHubCommand = registerGitHubCommand;
|
|
40
|
-
const http_1 = __importDefault(require("http"));
|
|
41
40
|
const open_1 = __importDefault(require("open"));
|
|
42
41
|
const cli_table3_1 = __importDefault(require("cli-table3"));
|
|
43
42
|
const chalk_1 = __importDefault(require("chalk"));
|
|
@@ -47,195 +46,10 @@ const api_1 = require("../lib/api");
|
|
|
47
46
|
const errors_1 = require("../lib/errors");
|
|
48
47
|
const analytics_1 = require("../lib/analytics");
|
|
49
48
|
const output_1 = require("../lib/output");
|
|
50
|
-
const
|
|
51
|
-
const
|
|
49
|
+
const POLL_INTERVAL_MS = 1500;
|
|
50
|
+
const POLL_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
|
|
51
|
+
const SETTINGS_REDIRECT_BASE = 'https://orchagent.io/settings';
|
|
52
52
|
// Helper functions
|
|
53
|
-
function successHtml() {
|
|
54
|
-
return `<!DOCTYPE html>
|
|
55
|
-
<html>
|
|
56
|
-
<head>
|
|
57
|
-
<meta charset="utf-8">
|
|
58
|
-
<title>orchagent CLI - GitHub Connected</title>
|
|
59
|
-
<style>
|
|
60
|
-
body {
|
|
61
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
62
|
-
display: flex;
|
|
63
|
-
align-items: center;
|
|
64
|
-
justify-content: center;
|
|
65
|
-
min-height: 100vh;
|
|
66
|
-
margin: 0;
|
|
67
|
-
background: #0a0a0a;
|
|
68
|
-
color: #fafafa;
|
|
69
|
-
}
|
|
70
|
-
.container {
|
|
71
|
-
text-align: center;
|
|
72
|
-
padding: 2rem;
|
|
73
|
-
}
|
|
74
|
-
.icon {
|
|
75
|
-
width: 64px;
|
|
76
|
-
height: 64px;
|
|
77
|
-
background: rgba(34, 197, 94, 0.1);
|
|
78
|
-
border-radius: 50%;
|
|
79
|
-
display: flex;
|
|
80
|
-
align-items: center;
|
|
81
|
-
justify-content: center;
|
|
82
|
-
margin: 0 auto 1.5rem;
|
|
83
|
-
}
|
|
84
|
-
.icon svg {
|
|
85
|
-
width: 32px;
|
|
86
|
-
height: 32px;
|
|
87
|
-
color: #22c55e;
|
|
88
|
-
}
|
|
89
|
-
h1 {
|
|
90
|
-
font-size: 1.5rem;
|
|
91
|
-
margin: 0 0 0.5rem;
|
|
92
|
-
}
|
|
93
|
-
p {
|
|
94
|
-
color: #a1a1aa;
|
|
95
|
-
margin: 0;
|
|
96
|
-
}
|
|
97
|
-
</style>
|
|
98
|
-
</head>
|
|
99
|
-
<body>
|
|
100
|
-
<div class="container">
|
|
101
|
-
<div class="icon">
|
|
102
|
-
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
103
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
|
|
104
|
-
</svg>
|
|
105
|
-
</div>
|
|
106
|
-
<h1>GitHub Connected</h1>
|
|
107
|
-
<p>You can close this tab and return to your terminal.</p>
|
|
108
|
-
</div>
|
|
109
|
-
</body>
|
|
110
|
-
</html>`;
|
|
111
|
-
}
|
|
112
|
-
function errorHtml(message) {
|
|
113
|
-
return `<!DOCTYPE html>
|
|
114
|
-
<html>
|
|
115
|
-
<head>
|
|
116
|
-
<meta charset="utf-8">
|
|
117
|
-
<title>orchagent CLI - GitHub Connection Error</title>
|
|
118
|
-
<style>
|
|
119
|
-
body {
|
|
120
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
121
|
-
display: flex;
|
|
122
|
-
align-items: center;
|
|
123
|
-
justify-content: center;
|
|
124
|
-
min-height: 100vh;
|
|
125
|
-
margin: 0;
|
|
126
|
-
background: #0a0a0a;
|
|
127
|
-
color: #fafafa;
|
|
128
|
-
}
|
|
129
|
-
.container {
|
|
130
|
-
text-align: center;
|
|
131
|
-
padding: 2rem;
|
|
132
|
-
}
|
|
133
|
-
.icon {
|
|
134
|
-
width: 64px;
|
|
135
|
-
height: 64px;
|
|
136
|
-
background: rgba(239, 68, 68, 0.1);
|
|
137
|
-
border-radius: 50%;
|
|
138
|
-
display: flex;
|
|
139
|
-
align-items: center;
|
|
140
|
-
justify-content: center;
|
|
141
|
-
margin: 0 auto 1.5rem;
|
|
142
|
-
}
|
|
143
|
-
.icon svg {
|
|
144
|
-
width: 32px;
|
|
145
|
-
height: 32px;
|
|
146
|
-
color: #ef4444;
|
|
147
|
-
}
|
|
148
|
-
h1 {
|
|
149
|
-
font-size: 1.5rem;
|
|
150
|
-
margin: 0 0 0.5rem;
|
|
151
|
-
}
|
|
152
|
-
p {
|
|
153
|
-
color: #a1a1aa;
|
|
154
|
-
margin: 0;
|
|
155
|
-
}
|
|
156
|
-
</style>
|
|
157
|
-
</head>
|
|
158
|
-
<body>
|
|
159
|
-
<div class="container">
|
|
160
|
-
<div class="icon">
|
|
161
|
-
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
162
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
|
163
|
-
</svg>
|
|
164
|
-
</div>
|
|
165
|
-
<h1>Connection Error</h1>
|
|
166
|
-
<p>${message}</p>
|
|
167
|
-
</div>
|
|
168
|
-
</body>
|
|
169
|
-
</html>`;
|
|
170
|
-
}
|
|
171
|
-
async function waitForGitHubCallback(port, timeoutMs) {
|
|
172
|
-
return new Promise((resolve, reject) => {
|
|
173
|
-
let resolved = false;
|
|
174
|
-
let server = null;
|
|
175
|
-
const cleanup = () => {
|
|
176
|
-
if (server) {
|
|
177
|
-
server.close();
|
|
178
|
-
server = null;
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
const timeout = setTimeout(() => {
|
|
182
|
-
if (!resolved) {
|
|
183
|
-
resolved = true;
|
|
184
|
-
cleanup();
|
|
185
|
-
reject(new errors_1.CliError('GitHub authentication timed out. Please try again.'));
|
|
186
|
-
}
|
|
187
|
-
}, timeoutMs);
|
|
188
|
-
server = http_1.default.createServer((req, res) => {
|
|
189
|
-
const url = new URL(req.url || '/', `http://127.0.0.1:${port}`);
|
|
190
|
-
if (url.pathname !== '/callback') {
|
|
191
|
-
res.writeHead(404);
|
|
192
|
-
res.end('Not Found');
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
const code = url.searchParams.get('code');
|
|
196
|
-
const state = url.searchParams.get('state');
|
|
197
|
-
const error = url.searchParams.get('error');
|
|
198
|
-
if (error) {
|
|
199
|
-
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
200
|
-
res.end(errorHtml(url.searchParams.get('error_description') || error));
|
|
201
|
-
if (!resolved) {
|
|
202
|
-
resolved = true;
|
|
203
|
-
clearTimeout(timeout);
|
|
204
|
-
cleanup();
|
|
205
|
-
reject(new errors_1.CliError(`GitHub authorization failed: ${error}`));
|
|
206
|
-
}
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
|
-
if (!code || !state) {
|
|
210
|
-
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
211
|
-
res.end(errorHtml('Missing code or state parameter'));
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
215
|
-
res.end(successHtml());
|
|
216
|
-
if (!resolved) {
|
|
217
|
-
resolved = true;
|
|
218
|
-
clearTimeout(timeout);
|
|
219
|
-
cleanup();
|
|
220
|
-
resolve({ code, state });
|
|
221
|
-
}
|
|
222
|
-
});
|
|
223
|
-
server.on('error', (err) => {
|
|
224
|
-
if (!resolved) {
|
|
225
|
-
resolved = true;
|
|
226
|
-
clearTimeout(timeout);
|
|
227
|
-
cleanup();
|
|
228
|
-
if (err.code === 'EADDRINUSE') {
|
|
229
|
-
reject(new errors_1.CliError(`Port ${port} is already in use. Try a different port with --port.`));
|
|
230
|
-
}
|
|
231
|
-
else {
|
|
232
|
-
reject(new errors_1.CliError(`Failed to start auth server: ${err.message}`));
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
});
|
|
236
|
-
server.listen(port, '127.0.0.1');
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
53
|
async function promptForSelection(items) {
|
|
240
54
|
if (!process.stdin.isTTY) {
|
|
241
55
|
return null;
|
|
@@ -271,38 +85,54 @@ async function promptForSelection(items) {
|
|
|
271
85
|
});
|
|
272
86
|
});
|
|
273
87
|
}
|
|
88
|
+
function sleep(ms) {
|
|
89
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
90
|
+
}
|
|
274
91
|
// Command implementations
|
|
275
|
-
async function connectGitHub(config
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
body: JSON.stringify({ redirect_uri: redirectUri }),
|
|
92
|
+
async function connectGitHub(config) {
|
|
93
|
+
// Step 1: Initialize the GitHub App install flow
|
|
94
|
+
const initResponse = await (0, api_1.request)(config, 'POST', '/github/install/init', {
|
|
95
|
+
body: JSON.stringify({ redirect_uri: SETTINGS_REDIRECT_BASE }),
|
|
280
96
|
headers: { 'Content-Type': 'application/json' },
|
|
281
97
|
});
|
|
282
|
-
// Step 2:
|
|
283
|
-
|
|
284
|
-
// Step 3: Open browser
|
|
285
|
-
process.stdout.write('Opening browser for GitHub authentication...\n');
|
|
98
|
+
// Step 2: Open browser for GitHub App installation
|
|
99
|
+
process.stdout.write('Opening browser to install the GitHub App...\n');
|
|
286
100
|
try {
|
|
287
|
-
await (0, open_1.default)(initResponse.
|
|
101
|
+
await (0, open_1.default)(initResponse.install_url);
|
|
288
102
|
}
|
|
289
103
|
catch {
|
|
290
|
-
|
|
104
|
+
// Headless or browser unavailable - print URL for manual copy/paste
|
|
105
|
+
process.stdout.write(`\nCould not open browser automatically.\n`);
|
|
106
|
+
process.stdout.write(`Please open this URL in your browser:\n\n`);
|
|
107
|
+
process.stdout.write(` ${initResponse.install_url}\n\n`);
|
|
291
108
|
}
|
|
292
|
-
// Step
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
109
|
+
// Step 3: Poll for completion
|
|
110
|
+
process.stdout.write('Waiting for GitHub App installation...\n');
|
|
111
|
+
const startTime = Date.now();
|
|
112
|
+
while (Date.now() - startTime < POLL_TIMEOUT_MS) {
|
|
113
|
+
await sleep(POLL_INTERVAL_MS);
|
|
114
|
+
const status = await (0, api_1.request)(config, 'GET', `/github/install/status?state=${encodeURIComponent(initResponse.state)}`);
|
|
115
|
+
if (status.status === 'completed') {
|
|
116
|
+
await (0, analytics_1.track)('cli_github_connect', { success: true });
|
|
117
|
+
process.stdout.write('\n');
|
|
118
|
+
process.stdout.write(`Connected to GitHub as ${chalk_1.default.bold(status.github_account_login)}\n`);
|
|
119
|
+
if (status.github_account_type) {
|
|
120
|
+
process.stdout.write(` Type: ${status.github_account_type}\n`);
|
|
121
|
+
}
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (status.status === 'failed') {
|
|
125
|
+
await (0, analytics_1.track)('cli_github_connect', { success: false });
|
|
126
|
+
throw new errors_1.CliError(`GitHub App installation failed: ${status.error_message || 'Unknown error'}`);
|
|
127
|
+
}
|
|
128
|
+
// Still pending - continue polling
|
|
129
|
+
}
|
|
130
|
+
throw new errors_1.CliError('GitHub App installation timed out after 5 minutes. Please try again.');
|
|
301
131
|
}
|
|
302
132
|
async function disconnectGitHub(config) {
|
|
303
|
-
await (0, api_1.request)(config, 'DELETE', '/github/
|
|
133
|
+
await (0, api_1.request)(config, 'DELETE', '/github/uninstall');
|
|
304
134
|
await (0, analytics_1.track)('cli_github_disconnect');
|
|
305
|
-
process.stdout.write('
|
|
135
|
+
process.stdout.write('GitHub App uninstalled.\n');
|
|
306
136
|
}
|
|
307
137
|
async function getGitHubStatus(config, json) {
|
|
308
138
|
const connection = await (0, api_1.request)(config, 'GET', '/github/connection');
|
|
@@ -317,52 +147,19 @@ async function getGitHubStatus(config, json) {
|
|
|
317
147
|
}
|
|
318
148
|
process.stdout.write(`GitHub Status:\n\n`);
|
|
319
149
|
process.stdout.write(` Connected: ${chalk_1.default.green('Yes')}\n`);
|
|
320
|
-
process.stdout.write(`
|
|
321
|
-
if (connection.
|
|
322
|
-
|
|
150
|
+
process.stdout.write(` Account: ${chalk_1.default.bold(connection.github_account_login)}\n`);
|
|
151
|
+
if (connection.github_account_type) {
|
|
152
|
+
process.stdout.write(` Type: ${connection.github_account_type === 'User' ? 'User' : 'Organization'}\n`);
|
|
153
|
+
}
|
|
154
|
+
if (connection.installed_at) {
|
|
155
|
+
const date = new Date(connection.installed_at).toLocaleDateString();
|
|
323
156
|
process.stdout.write(` Since: ${date}\n`);
|
|
324
157
|
}
|
|
325
|
-
if (connection.
|
|
326
|
-
process.stdout.write(`
|
|
158
|
+
if (connection.suspended_at) {
|
|
159
|
+
process.stdout.write(` Status: ${chalk_1.default.yellow('Suspended')} (since ${new Date(connection.suspended_at).toLocaleDateString()})\n`);
|
|
327
160
|
}
|
|
328
161
|
process.stdout.write('\n');
|
|
329
162
|
}
|
|
330
|
-
async function listGitHubRepos(config, search, json) {
|
|
331
|
-
const params = new URLSearchParams();
|
|
332
|
-
if (search) {
|
|
333
|
-
params.append('search', search);
|
|
334
|
-
}
|
|
335
|
-
const queryStr = params.toString();
|
|
336
|
-
const repos = await (0, api_1.request)(config, 'GET', `/github/repos${queryStr ? `?${queryStr}` : ''}`);
|
|
337
|
-
await (0, analytics_1.track)('cli_github_list', { search: !!search, count: repos.length });
|
|
338
|
-
if (json) {
|
|
339
|
-
(0, output_1.printJson)(repos);
|
|
340
|
-
return;
|
|
341
|
-
}
|
|
342
|
-
if (repos.length === 0) {
|
|
343
|
-
process.stdout.write('No repositories found.\n');
|
|
344
|
-
if (search) {
|
|
345
|
-
process.stdout.write(`\nTry a different search term or run without --search to see all repos.\n`);
|
|
346
|
-
}
|
|
347
|
-
return;
|
|
348
|
-
}
|
|
349
|
-
const table = new cli_table3_1.default({
|
|
350
|
-
head: [
|
|
351
|
-
chalk_1.default.bold('Repository'),
|
|
352
|
-
chalk_1.default.bold('Private'),
|
|
353
|
-
chalk_1.default.bold('Last Pushed'),
|
|
354
|
-
],
|
|
355
|
-
});
|
|
356
|
-
repos.forEach((repo) => {
|
|
357
|
-
const visibility = repo.private ? chalk_1.default.yellow('Yes') : chalk_1.default.green('No');
|
|
358
|
-
const pushed = repo.pushed_at
|
|
359
|
-
? new Date(repo.pushed_at).toLocaleDateString()
|
|
360
|
-
: '-';
|
|
361
|
-
table.push([repo.full_name, visibility, pushed]);
|
|
362
|
-
});
|
|
363
|
-
process.stdout.write(`${table.toString()}\n`);
|
|
364
|
-
process.stdout.write(`\nFound ${repos.length} repositor${repos.length === 1 ? 'y' : 'ies'}.\n`);
|
|
365
|
-
}
|
|
366
163
|
async function scanGitHubRepo(config, repo, json) {
|
|
367
164
|
// Parse owner/repo format
|
|
368
165
|
const parts = repo.split('/');
|
|
@@ -371,7 +168,8 @@ async function scanGitHubRepo(config, repo, json) {
|
|
|
371
168
|
`Use owner/repo format, e.g.: orchagent github scan myorg/myrepo`);
|
|
372
169
|
}
|
|
373
170
|
const [owner, repoName] = parts;
|
|
374
|
-
const
|
|
171
|
+
const response = await (0, api_1.request)(config, 'GET', `/github/repos/${owner}/${repoName}/scan`);
|
|
172
|
+
const results = response.items;
|
|
375
173
|
await (0, analytics_1.track)('cli_github_scan', { repo, found: results.length });
|
|
376
174
|
if (json) {
|
|
377
175
|
(0, output_1.printJson)(results);
|
|
@@ -392,7 +190,7 @@ async function scanGitHubRepo(config, repo, json) {
|
|
|
392
190
|
],
|
|
393
191
|
});
|
|
394
192
|
results.forEach((item) => {
|
|
395
|
-
const typeLabel = item.type === 'skill' ? chalk_1.default.cyan('skill') : chalk_1.default.magenta(
|
|
193
|
+
const typeLabel = item.type === 'skill' ? chalk_1.default.cyan('skill') : chalk_1.default.magenta(item.type);
|
|
396
194
|
table.push([typeLabel, item.path, item.name || '-']);
|
|
397
195
|
});
|
|
398
196
|
process.stdout.write(`${table.toString()}\n`);
|
|
@@ -401,13 +199,12 @@ async function scanGitHubRepo(config, repo, json) {
|
|
|
401
199
|
return results;
|
|
402
200
|
}
|
|
403
201
|
async function importFromGitHub(config, repo, options) {
|
|
404
|
-
//
|
|
202
|
+
// Validate owner/repo format
|
|
405
203
|
const parts = repo.split('/');
|
|
406
204
|
if (parts.length !== 2) {
|
|
407
205
|
throw new errors_1.CliError(`Invalid repository format: ${repo}\n\n` +
|
|
408
206
|
`Use owner/repo format, e.g.: orchagent github import myorg/myrepo`);
|
|
409
207
|
}
|
|
410
|
-
const [owner, repoName] = parts;
|
|
411
208
|
let selectedPath = options.path;
|
|
412
209
|
// If no path specified, scan first and let user choose
|
|
413
210
|
if (!selectedPath) {
|
|
@@ -433,8 +230,7 @@ async function importFromGitHub(config, repo, options) {
|
|
|
433
230
|
const isPublic = options.private ? false : true;
|
|
434
231
|
const importResult = await (0, api_1.request)(config, 'POST', '/github/import', {
|
|
435
232
|
body: JSON.stringify({
|
|
436
|
-
|
|
437
|
-
repo: repoName,
|
|
233
|
+
repo,
|
|
438
234
|
path: selectedPath,
|
|
439
235
|
is_public: isPublic,
|
|
440
236
|
name: options.name,
|
|
@@ -445,21 +241,48 @@ async function importFromGitHub(config, repo, options) {
|
|
|
445
241
|
repo,
|
|
446
242
|
path: selectedPath,
|
|
447
243
|
is_public: isPublic,
|
|
448
|
-
type: importResult.type,
|
|
244
|
+
type: importResult.agent.type,
|
|
449
245
|
});
|
|
450
246
|
if (options.json) {
|
|
451
247
|
(0, output_1.printJson)(importResult);
|
|
452
248
|
return;
|
|
453
249
|
}
|
|
454
250
|
process.stdout.write('\n');
|
|
455
|
-
process.stdout.write(`Imported ${chalk_1.default.bold(importResult.name)} from ${repo}\n`);
|
|
251
|
+
process.stdout.write(`Imported ${chalk_1.default.bold(importResult.agent.name)} from ${repo}\n`);
|
|
456
252
|
process.stdout.write('\n');
|
|
457
|
-
process.stdout.write(` Agent: ${importResult.
|
|
458
|
-
process.stdout.write(` Version: ${importResult.version}\n`);
|
|
459
|
-
process.stdout.write(` Type: ${importResult.type}\n`);
|
|
253
|
+
process.stdout.write(` Agent: ${importResult.agent.name}\n`);
|
|
254
|
+
process.stdout.write(` Version: ${importResult.agent.version}\n`);
|
|
255
|
+
process.stdout.write(` Type: ${importResult.agent.type}\n`);
|
|
460
256
|
process.stdout.write(` Public: ${isPublic ? chalk_1.default.green('Yes') : chalk_1.default.yellow('No')}\n`);
|
|
461
257
|
process.stdout.write('\n');
|
|
462
|
-
|
|
258
|
+
}
|
|
259
|
+
async function getSyncConfig(config, agentId, options) {
|
|
260
|
+
// If --set-auto-publish is specified, update config first
|
|
261
|
+
if (options.setAutoPublish !== undefined) {
|
|
262
|
+
const autoPublish = options.setAutoPublish === 'true';
|
|
263
|
+
await (0, api_1.request)(config, 'PATCH', `/github/agents/${agentId}/sync-config`, {
|
|
264
|
+
body: JSON.stringify({ auto_publish: autoPublish }),
|
|
265
|
+
headers: { 'Content-Type': 'application/json' },
|
|
266
|
+
});
|
|
267
|
+
process.stdout.write(`Updated auto_publish to ${chalk_1.default.bold(String(autoPublish))} for agent ${agentId}\n`);
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
const syncConfig = await (0, api_1.request)(config, 'GET', `/github/agents/${agentId}/sync-config`);
|
|
271
|
+
if (options.json) {
|
|
272
|
+
(0, output_1.printJson)(syncConfig);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
process.stdout.write(`Sync Config for ${chalk_1.default.bold(agentId)}:\n\n`);
|
|
276
|
+
process.stdout.write(` Auto-publish: ${syncConfig.auto_publish ? chalk_1.default.green('enabled') : chalk_1.default.yellow('disabled')}\n`);
|
|
277
|
+
if (syncConfig.sync_status) {
|
|
278
|
+
process.stdout.write(` Sync status: ${syncConfig.sync_status}\n`);
|
|
279
|
+
}
|
|
280
|
+
process.stdout.write('\n');
|
|
281
|
+
}
|
|
282
|
+
async function approveSync(config, agentId) {
|
|
283
|
+
await (0, api_1.request)(config, 'POST', `/github/agents/${agentId}/approve`);
|
|
284
|
+
await (0, analytics_1.track)('cli_github_approve', { agent_id: agentId });
|
|
285
|
+
process.stdout.write(`Approved pending sync for agent ${chalk_1.default.bold(agentId)}.\n`);
|
|
463
286
|
}
|
|
464
287
|
// Command registration
|
|
465
288
|
function registerGitHubCommand(program) {
|
|
@@ -468,22 +291,17 @@ function registerGitHubCommand(program) {
|
|
|
468
291
|
.description('Connect to GitHub and import agents');
|
|
469
292
|
github
|
|
470
293
|
.command('connect')
|
|
471
|
-
.description('
|
|
472
|
-
.
|
|
473
|
-
.action(async (options) => {
|
|
294
|
+
.description('Install the GitHub App to connect your account')
|
|
295
|
+
.action(async () => {
|
|
474
296
|
const config = await (0, config_1.getResolvedConfig)();
|
|
475
297
|
if (!config.apiKey) {
|
|
476
298
|
throw new errors_1.CliError('Missing API key. Run `orchagent login` first.');
|
|
477
299
|
}
|
|
478
|
-
|
|
479
|
-
if (isNaN(port) || port < 1024 || port > 65535) {
|
|
480
|
-
throw new errors_1.CliError('Port must be a number between 1024 and 65535');
|
|
481
|
-
}
|
|
482
|
-
await connectGitHub(config, port);
|
|
300
|
+
await connectGitHub(config);
|
|
483
301
|
});
|
|
484
302
|
github
|
|
485
303
|
.command('disconnect')
|
|
486
|
-
.description('Remove GitHub
|
|
304
|
+
.description('Remove GitHub App installation')
|
|
487
305
|
.action(async () => {
|
|
488
306
|
const config = await (0, config_1.getResolvedConfig)();
|
|
489
307
|
if (!config.apiKey) {
|
|
@@ -502,18 +320,6 @@ function registerGitHubCommand(program) {
|
|
|
502
320
|
}
|
|
503
321
|
await getGitHubStatus(config, options.json || false);
|
|
504
322
|
});
|
|
505
|
-
github
|
|
506
|
-
.command('list')
|
|
507
|
-
.description('List accessible GitHub repositories')
|
|
508
|
-
.option('--search <query>', 'Filter repositories by name')
|
|
509
|
-
.option('--json', 'Output raw JSON')
|
|
510
|
-
.action(async (options) => {
|
|
511
|
-
const config = await (0, config_1.getResolvedConfig)();
|
|
512
|
-
if (!config.apiKey) {
|
|
513
|
-
throw new errors_1.CliError('Missing API key. Run `orchagent login` first.');
|
|
514
|
-
}
|
|
515
|
-
await listGitHubRepos(config, options.search, options.json || false);
|
|
516
|
-
});
|
|
517
323
|
github
|
|
518
324
|
.command('scan <repo>')
|
|
519
325
|
.description('Scan a repository for agents and skills')
|
|
@@ -540,4 +346,29 @@ function registerGitHubCommand(program) {
|
|
|
540
346
|
}
|
|
541
347
|
await importFromGitHub(config, repo, options);
|
|
542
348
|
});
|
|
349
|
+
github
|
|
350
|
+
.command('sync-config <agent>')
|
|
351
|
+
.description('View or update sync configuration for a GitHub-linked agent')
|
|
352
|
+
.option('--set-auto-publish <value>', 'Set auto_publish (true or false)')
|
|
353
|
+
.option('--json', 'Output raw JSON')
|
|
354
|
+
.action(async (agent, options) => {
|
|
355
|
+
const config = await (0, config_1.getResolvedConfig)();
|
|
356
|
+
if (!config.apiKey) {
|
|
357
|
+
throw new errors_1.CliError('Missing API key. Run `orchagent login` first.');
|
|
358
|
+
}
|
|
359
|
+
if (options.setAutoPublish !== undefined && options.setAutoPublish !== 'true' && options.setAutoPublish !== 'false') {
|
|
360
|
+
throw new errors_1.CliError('--set-auto-publish must be "true" or "false"');
|
|
361
|
+
}
|
|
362
|
+
await getSyncConfig(config, agent, options);
|
|
363
|
+
});
|
|
364
|
+
github
|
|
365
|
+
.command('approve <agent_id>')
|
|
366
|
+
.description('Approve a pending GitHub sync for an agent')
|
|
367
|
+
.action(async (agentId) => {
|
|
368
|
+
const config = await (0, config_1.getResolvedConfig)();
|
|
369
|
+
if (!config.apiKey) {
|
|
370
|
+
throw new errors_1.CliError('Missing API key. Run `orchagent login` first.');
|
|
371
|
+
}
|
|
372
|
+
await approveSync(config, agentId);
|
|
373
|
+
});
|
|
543
374
|
}
|
package/dist/commands/init.js
CHANGED
|
@@ -248,7 +248,7 @@ function registerInitCommand(program) {
|
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
250
|
if (initMode.flavor === 'direct_llm' && runMode === 'always_on') {
|
|
251
|
-
throw new errors_1.CliError("run_mode=always_on requires
|
|
251
|
+
throw new errors_1.CliError("run_mode=always_on requires runtime.command in orchagent.json (e.g. \"runtime\": { \"command\": \"python main.py\" }).");
|
|
252
252
|
}
|
|
253
253
|
// Create manifest and type-specific files
|
|
254
254
|
const manifest = JSON.parse(MANIFEST_TEMPLATE);
|
package/dist/commands/pull.js
CHANGED
|
@@ -36,6 +36,11 @@ function resolveEngine(data) {
|
|
|
36
36
|
if (ee === 'direct_llm' || ee === 'managed_loop' || ee === 'code_runtime') {
|
|
37
37
|
return ee;
|
|
38
38
|
}
|
|
39
|
+
const runtimeCommand = data.runtime?.command;
|
|
40
|
+
if (typeof runtimeCommand === 'string' && runtimeCommand.trim())
|
|
41
|
+
return 'code_runtime';
|
|
42
|
+
if (data.loop && Object.keys(data.loop).length > 0)
|
|
43
|
+
return 'managed_loop';
|
|
39
44
|
const normalized = (data.type || '').toLowerCase();
|
|
40
45
|
if (normalized === 'tool' || normalized === 'code')
|
|
41
46
|
return 'code_runtime';
|
|
@@ -43,6 +48,15 @@ function resolveEngine(data) {
|
|
|
43
48
|
return 'managed_loop';
|
|
44
49
|
return 'direct_llm';
|
|
45
50
|
}
|
|
51
|
+
function commandForEntrypoint(entrypoint) {
|
|
52
|
+
if (entrypoint.endsWith('.js')
|
|
53
|
+
|| entrypoint.endsWith('.mjs')
|
|
54
|
+
|| entrypoint.endsWith('.cjs')
|
|
55
|
+
|| entrypoint.endsWith('.ts')) {
|
|
56
|
+
return `node ${entrypoint}`;
|
|
57
|
+
}
|
|
58
|
+
return `python ${entrypoint}`;
|
|
59
|
+
}
|
|
46
60
|
// ─── Agent Resolution ───────────────────────────────────────────────────────
|
|
47
61
|
async function resolveAgent(config, org, agent, version) {
|
|
48
62
|
// 1. Try public download endpoint
|
|
@@ -55,10 +69,13 @@ async function resolveAgent(config, org, agent, version) {
|
|
|
55
69
|
type: data.type || 'agent',
|
|
56
70
|
run_mode: data.run_mode,
|
|
57
71
|
execution_engine: data.execution_engine,
|
|
72
|
+
runtime: data.runtime,
|
|
73
|
+
loop: data.loop,
|
|
58
74
|
callable: data.callable,
|
|
59
75
|
prompt: data.prompt,
|
|
60
76
|
input_schema: data.input_schema,
|
|
61
77
|
output_schema: data.output_schema,
|
|
78
|
+
dependencies: data.dependencies,
|
|
62
79
|
supported_providers: data.supported_providers,
|
|
63
80
|
default_models: data.default_models,
|
|
64
81
|
default_skills: data.default_skills,
|
|
@@ -133,7 +150,7 @@ async function tryOwnerFallback(config, org, agent, version) {
|
|
|
133
150
|
}
|
|
134
151
|
async function resolveFromMyAgents(config, agent, version, org) {
|
|
135
152
|
const agents = await (0, api_1.listMyAgents)(config);
|
|
136
|
-
const matching = agents.filter(a => a.name === agent);
|
|
153
|
+
const matching = agents.filter(a => a.name === agent && a.org_slug === org);
|
|
137
154
|
if (matching.length === 0)
|
|
138
155
|
return null;
|
|
139
156
|
let target;
|
|
@@ -157,10 +174,13 @@ function mapAgentToPullData(agent) {
|
|
|
157
174
|
type: agent.type,
|
|
158
175
|
run_mode: agent.run_mode ?? null,
|
|
159
176
|
execution_engine: agent.execution_engine ?? null,
|
|
177
|
+
runtime: agent.runtime ?? null,
|
|
178
|
+
loop: agent.loop ?? null,
|
|
160
179
|
callable: agent.callable,
|
|
161
180
|
prompt: agent.prompt,
|
|
162
181
|
input_schema: agent.input_schema,
|
|
163
182
|
output_schema: agent.output_schema,
|
|
183
|
+
dependencies: agent.manifest?.dependencies,
|
|
164
184
|
supported_providers: agent.supported_providers,
|
|
165
185
|
default_models: agent.default_models,
|
|
166
186
|
tags: agent.tags,
|
|
@@ -207,6 +227,16 @@ function buildManifest(data) {
|
|
|
207
227
|
// Engine-specific fields
|
|
208
228
|
const engine = resolveEngine(data);
|
|
209
229
|
if (engine === 'code_runtime') {
|
|
230
|
+
const runtime = (data.runtime && typeof data.runtime === 'object' && Object.keys(data.runtime).length > 0)
|
|
231
|
+
? { ...data.runtime }
|
|
232
|
+
: undefined;
|
|
233
|
+
const runtimeCommand = (typeof runtime?.command === 'string' && runtime.command.trim())
|
|
234
|
+
? runtime.command
|
|
235
|
+
: (data.run_command?.trim()
|
|
236
|
+
|| (data.entrypoint ? commandForEntrypoint(data.entrypoint) : undefined));
|
|
237
|
+
if (runtimeCommand) {
|
|
238
|
+
manifest.runtime = { ...(runtime || {}), command: runtimeCommand };
|
|
239
|
+
}
|
|
210
240
|
if (data.entrypoint && data.entrypoint !== 'sandbox_main.py') {
|
|
211
241
|
manifest.entrypoint = data.entrypoint;
|
|
212
242
|
}
|
|
@@ -217,9 +247,32 @@ function buildManifest(data) {
|
|
|
217
247
|
if (data.run_command)
|
|
218
248
|
manifest.run_command = data.run_command;
|
|
219
249
|
}
|
|
250
|
+
if (engine === 'managed_loop') {
|
|
251
|
+
const loop = (data.loop && typeof data.loop === 'object' && Object.keys(data.loop).length > 0)
|
|
252
|
+
? { ...data.loop }
|
|
253
|
+
: undefined;
|
|
254
|
+
if (loop) {
|
|
255
|
+
manifest.loop = loop;
|
|
256
|
+
const loopCustomTools = loop.custom_tools;
|
|
257
|
+
if (Array.isArray(loopCustomTools) && loopCustomTools.length > 0) {
|
|
258
|
+
manifest.custom_tools = loopCustomTools;
|
|
259
|
+
}
|
|
260
|
+
const loopMaxTurns = loop.max_turns;
|
|
261
|
+
if (typeof loopMaxTurns === 'number') {
|
|
262
|
+
manifest.max_turns = loopMaxTurns;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
220
266
|
// Include orchestration manifest if present (for dependencies, etc.)
|
|
221
267
|
if (data.manifest && typeof data.manifest === 'object') {
|
|
222
268
|
const m = { ...data.manifest };
|
|
269
|
+
if (data.dependencies
|
|
270
|
+
&& data.dependencies.length > 0
|
|
271
|
+
&& (!Array.isArray(m.dependencies)
|
|
272
|
+
|| m.dependencies?.length === 0)) {
|
|
273
|
+
;
|
|
274
|
+
m.dependencies = data.dependencies;
|
|
275
|
+
}
|
|
223
276
|
// Clean up fields that are already top-level
|
|
224
277
|
delete m.runtime;
|
|
225
278
|
delete m.loop;
|
|
@@ -227,6 +280,9 @@ function buildManifest(data) {
|
|
|
227
280
|
manifest.manifest = m;
|
|
228
281
|
}
|
|
229
282
|
}
|
|
283
|
+
else if (data.dependencies && data.dependencies.length > 0) {
|
|
284
|
+
manifest.manifest = { dependencies: data.dependencies };
|
|
285
|
+
}
|
|
230
286
|
return manifest;
|
|
231
287
|
}
|
|
232
288
|
// ─── Bundle Download + Extraction ───────────────────────────────────────────
|
|
@@ -235,8 +291,11 @@ async function downloadBundle(config, org, agent, version, agentId) {
|
|
|
235
291
|
return await (0, api_1.downloadCodeBundle)(config, org, agent, version);
|
|
236
292
|
}
|
|
237
293
|
catch (err) {
|
|
238
|
-
if (!(err instanceof api_1.ApiError)
|
|
294
|
+
if (!(err instanceof api_1.ApiError))
|
|
295
|
+
throw err;
|
|
296
|
+
if (err.status !== 404 && !(err.status === 403 && config.apiKey && agentId)) {
|
|
239
297
|
throw err;
|
|
298
|
+
}
|
|
240
299
|
}
|
|
241
300
|
if (config.apiKey && agentId) {
|
|
242
301
|
try {
|
package/dist/commands/service.js
CHANGED
|
@@ -174,7 +174,7 @@ function registerServiceCommand(program) {
|
|
|
174
174
|
process.stdout.write(` ${chalk_1.default.bold('Name:')} ${svc.service_name}\n`);
|
|
175
175
|
process.stdout.write(` ${chalk_1.default.bold('Agent:')} ${svc.agent_name}@${svc.agent_version}\n`);
|
|
176
176
|
process.stdout.write(` ${chalk_1.default.bold('State:')} ${stateColor(svc.current_state)}\n`);
|
|
177
|
-
process.stdout.write(` ${chalk_1.default.bold('URL:')} ${svc.cloud_run_url || '-'}\n`);
|
|
177
|
+
process.stdout.write(` ${chalk_1.default.bold('URL:')} ${svc.provider_url || svc.cloud_run_url || '-'}\n`);
|
|
178
178
|
process.stdout.write(`\n`);
|
|
179
179
|
process.stdout.write(chalk_1.default.gray(`View logs: orch service logs ${svc.id}\n`));
|
|
180
180
|
}
|
|
@@ -334,8 +334,8 @@ function registerServiceCommand(program) {
|
|
|
334
334
|
process.stdout.write(` Fail Streak: ${chalk_1.default.red(String(svc.consecutive_restart_failures))} / ${svc.max_restart_failures}\n`);
|
|
335
335
|
}
|
|
336
336
|
process.stdout.write(` Instances: ${svc.min_instances}-${svc.max_instances}\n`);
|
|
337
|
-
process.stdout.write(`
|
|
338
|
-
process.stdout.write(` URL: ${svc.cloud_run_url || '-'}\n`);
|
|
337
|
+
process.stdout.write(` Service ID: ${svc.provider_service_id || svc.cloud_run_service || '-'}\n`);
|
|
338
|
+
process.stdout.write(` URL: ${svc.provider_url || svc.cloud_run_url || '-'}\n`);
|
|
339
339
|
process.stdout.write(` Deployed: ${formatDate(svc.last_deployed_at)}\n`);
|
|
340
340
|
process.stdout.write(` Last Restart: ${formatDate(svc.last_restart_at)}\n`);
|
|
341
341
|
if (svc.last_error) {
|
package/package.json
CHANGED