@orchagent/cli 0.2.10 → 0.2.12
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/delete.js +90 -0
- package/dist/commands/doctor.js +27 -0
- package/dist/commands/github.js +543 -0
- package/dist/commands/index.js +6 -0
- package/dist/commands/run.js +10 -3
- package/dist/commands/workspace.js +133 -0
- package/dist/lib/api.js +15 -0
- package/dist/lib/auth-errors.js +27 -0
- package/dist/lib/browser-auth.js +5 -8
- package/dist/lib/doctor/checks/auth.js +115 -0
- package/dist/lib/doctor/checks/config.js +119 -0
- package/dist/lib/doctor/checks/connectivity.js +109 -0
- package/dist/lib/doctor/checks/environment.js +151 -0
- package/dist/lib/doctor/checks/llm.js +108 -0
- package/dist/lib/doctor/index.js +19 -0
- package/dist/lib/doctor/output.js +105 -0
- package/dist/lib/doctor/runner.js +68 -0
- package/dist/lib/doctor/types.js +2 -0
- package/dist/lib/llm-errors.js +79 -0
- package/dist/lib/llm.js +4 -3
- package/package.json +1 -1
|
@@ -0,0 +1,90 @@
|
|
|
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.registerDeleteCommand = registerDeleteCommand;
|
|
7
|
+
const promises_1 = __importDefault(require("readline/promises"));
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const config_1 = require("../lib/config");
|
|
10
|
+
const api_1 = require("../lib/api");
|
|
11
|
+
const errors_1 = require("../lib/errors");
|
|
12
|
+
const analytics_1 = require("../lib/analytics");
|
|
13
|
+
async function promptText(message) {
|
|
14
|
+
const rl = promises_1.default.createInterface({
|
|
15
|
+
input: process.stdin,
|
|
16
|
+
output: process.stdout,
|
|
17
|
+
});
|
|
18
|
+
const answer = await rl.question(message);
|
|
19
|
+
rl.close();
|
|
20
|
+
return answer.trim();
|
|
21
|
+
}
|
|
22
|
+
async function promptConfirm(message) {
|
|
23
|
+
const answer = await promptText(`${message} (y/N): `);
|
|
24
|
+
return answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes';
|
|
25
|
+
}
|
|
26
|
+
function registerDeleteCommand(program) {
|
|
27
|
+
program
|
|
28
|
+
.command('delete <agent-name>')
|
|
29
|
+
.description('Delete an agent')
|
|
30
|
+
.option('--version <version>', 'Specific version to delete (default: latest)')
|
|
31
|
+
.option('-y, --yes', 'Skip confirmation prompt')
|
|
32
|
+
.action(async (agentName, options) => {
|
|
33
|
+
const config = await (0, config_1.getResolvedConfig)();
|
|
34
|
+
if (!config.apiKey) {
|
|
35
|
+
throw new errors_1.CliError('Not logged in. Run `orch login` first.');
|
|
36
|
+
}
|
|
37
|
+
process.stdout.write('Finding agent...\n');
|
|
38
|
+
// Find the agent
|
|
39
|
+
const agents = await (0, api_1.listMyAgents)(config);
|
|
40
|
+
const matching = agents.filter(a => a.name === agentName);
|
|
41
|
+
if (matching.length === 0) {
|
|
42
|
+
throw new errors_1.CliError(`Agent '${agentName}' not found`);
|
|
43
|
+
}
|
|
44
|
+
// Select version
|
|
45
|
+
let agent;
|
|
46
|
+
if (options.version) {
|
|
47
|
+
agent = matching.find(a => a.version === options.version);
|
|
48
|
+
if (!agent) {
|
|
49
|
+
throw new errors_1.CliError(`Version '${options.version}' not found for agent '${agentName}'`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
// Get latest version
|
|
54
|
+
agent = matching.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())[0];
|
|
55
|
+
}
|
|
56
|
+
// Check if confirmation is required
|
|
57
|
+
const deleteCheck = await (0, api_1.checkAgentDelete)(config, agent.id);
|
|
58
|
+
// Show agent info
|
|
59
|
+
process.stdout.write(`\n${chalk_1.default.bold('Agent:')} ${agent.name}@${agent.version}\n`);
|
|
60
|
+
if (deleteCheck.stars_count > 0 || deleteCheck.fork_count > 0) {
|
|
61
|
+
process.stdout.write(`${chalk_1.default.bold('Stars:')} ${deleteCheck.stars_count} ${chalk_1.default.bold('Forks:')} ${deleteCheck.fork_count}\n`);
|
|
62
|
+
}
|
|
63
|
+
process.stdout.write('\n');
|
|
64
|
+
// Handle confirmation
|
|
65
|
+
if (!options.yes) {
|
|
66
|
+
if (deleteCheck.requires_confirmation) {
|
|
67
|
+
process.stdout.write(chalk_1.default.yellow('Warning: This agent has stars or forks. Type the agent name to confirm deletion.\n\n'));
|
|
68
|
+
const confirmName = await promptText(`Type "${agent.name}" to confirm deletion: `);
|
|
69
|
+
if (confirmName !== agent.name) {
|
|
70
|
+
process.stdout.write(chalk_1.default.red('\nDeletion cancelled. Name did not match.\n'));
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
const confirmed = await promptConfirm(`Delete ${agent.name}@${agent.version}?`);
|
|
76
|
+
if (!confirmed) {
|
|
77
|
+
process.stdout.write(chalk_1.default.gray('Deletion cancelled.\n'));
|
|
78
|
+
process.exit(0);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Perform deletion
|
|
83
|
+
process.stdout.write('Deleting agent...\n');
|
|
84
|
+
const confirmationName = deleteCheck.requires_confirmation ? agent.name : undefined;
|
|
85
|
+
await (0, api_1.deleteAgent)(config, agent.id, confirmationName);
|
|
86
|
+
await (0, analytics_1.track)('cli_delete', { agent_name: agent.name, version: agent.version });
|
|
87
|
+
process.stdout.write(`✓ Deleted ${agent.name}@${agent.version}\n`);
|
|
88
|
+
process.stdout.write(chalk_1.default.gray('\nData will be retained for 30 days before permanent deletion.\n'));
|
|
89
|
+
});
|
|
90
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerDoctorCommand = registerDoctorCommand;
|
|
4
|
+
const doctor_1 = require("../lib/doctor");
|
|
5
|
+
const output_1 = require("../lib/output");
|
|
6
|
+
function registerDoctorCommand(program) {
|
|
7
|
+
program
|
|
8
|
+
.command('doctor')
|
|
9
|
+
.description('Diagnose setup issues with OrchAgent CLI')
|
|
10
|
+
.option('-v, --verbose', 'Show detailed output for each check')
|
|
11
|
+
.option('--json', 'Output results as JSON')
|
|
12
|
+
.action(async (options) => {
|
|
13
|
+
const results = await (0, doctor_1.runAllChecks)();
|
|
14
|
+
const summary = (0, doctor_1.calculateSummary)(results);
|
|
15
|
+
if (options.json) {
|
|
16
|
+
(0, output_1.printJson)((0, doctor_1.formatJsonOutput)(results, summary));
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
(0, doctor_1.printHumanOutput)(results, summary, options.verbose ?? false);
|
|
20
|
+
}
|
|
21
|
+
// Exit with code 1 if any errors or warnings (enables scripting)
|
|
22
|
+
const hasIssues = summary.errors > 0 || summary.warnings > 0;
|
|
23
|
+
if (hasIssues) {
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
@@ -0,0 +1,543 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.registerGitHubCommand = registerGitHubCommand;
|
|
40
|
+
const http_1 = __importDefault(require("http"));
|
|
41
|
+
const open_1 = __importDefault(require("open"));
|
|
42
|
+
const cli_table3_1 = __importDefault(require("cli-table3"));
|
|
43
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
44
|
+
const readline = __importStar(require("readline"));
|
|
45
|
+
const config_1 = require("../lib/config");
|
|
46
|
+
const api_1 = require("../lib/api");
|
|
47
|
+
const errors_1 = require("../lib/errors");
|
|
48
|
+
const analytics_1 = require("../lib/analytics");
|
|
49
|
+
const output_1 = require("../lib/output");
|
|
50
|
+
const DEFAULT_AUTH_PORT = 8375;
|
|
51
|
+
const AUTH_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
|
|
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
|
+
async function promptForSelection(items) {
|
|
240
|
+
if (!process.stdin.isTTY) {
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
process.stdout.write('\nSelect an item to import (enter number, or "q" to quit):\n\n');
|
|
244
|
+
items.forEach((item, idx) => {
|
|
245
|
+
process.stdout.write(` ${idx + 1}. [${item.type}] ${item.path}`);
|
|
246
|
+
if (item.name) {
|
|
247
|
+
process.stdout.write(` (${item.name})`);
|
|
248
|
+
}
|
|
249
|
+
process.stdout.write('\n');
|
|
250
|
+
});
|
|
251
|
+
process.stdout.write('\n');
|
|
252
|
+
const rl = readline.createInterface({
|
|
253
|
+
input: process.stdin,
|
|
254
|
+
output: process.stdout,
|
|
255
|
+
});
|
|
256
|
+
return new Promise((resolve) => {
|
|
257
|
+
rl.question('Choice: ', (answer) => {
|
|
258
|
+
rl.close();
|
|
259
|
+
const trimmed = answer.trim().toLowerCase();
|
|
260
|
+
if (trimmed === 'q' || trimmed === '') {
|
|
261
|
+
resolve(null);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const num = parseInt(trimmed, 10);
|
|
265
|
+
if (isNaN(num) || num < 1 || num > items.length) {
|
|
266
|
+
process.stdout.write('Invalid selection.\n');
|
|
267
|
+
resolve(null);
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
resolve(items[num - 1]);
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
// Command implementations
|
|
275
|
+
async function connectGitHub(config, port) {
|
|
276
|
+
const redirectUri = `http://127.0.0.1:${port}/callback`;
|
|
277
|
+
// Step 1: Initialize the GitHub OAuth flow
|
|
278
|
+
const initResponse = await (0, api_1.request)(config, 'POST', '/github/connect/init', {
|
|
279
|
+
body: JSON.stringify({ redirect_uri: redirectUri }),
|
|
280
|
+
headers: { 'Content-Type': 'application/json' },
|
|
281
|
+
});
|
|
282
|
+
// Step 2: Start local server to receive callback
|
|
283
|
+
const callbackPromise = waitForGitHubCallback(port, AUTH_TIMEOUT_MS);
|
|
284
|
+
// Step 3: Open browser
|
|
285
|
+
process.stdout.write('Opening browser for GitHub authentication...\n');
|
|
286
|
+
try {
|
|
287
|
+
await (0, open_1.default)(initResponse.auth_url);
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
process.stdout.write(`\nPlease open this URL in your browser:\n${initResponse.auth_url}\n\n`);
|
|
291
|
+
}
|
|
292
|
+
// Step 4: Wait for callback
|
|
293
|
+
const { code, state } = await callbackPromise;
|
|
294
|
+
// Step 5: Exchange code for connection
|
|
295
|
+
const callbackResponse = await (0, api_1.request)(config, 'POST', '/github/connect/callback', {
|
|
296
|
+
body: JSON.stringify({ code, state }),
|
|
297
|
+
headers: { 'Content-Type': 'application/json' },
|
|
298
|
+
});
|
|
299
|
+
await (0, analytics_1.track)('cli_github_connect', { success: true });
|
|
300
|
+
process.stdout.write(`\nConnected to GitHub as ${chalk_1.default.bold(callbackResponse.username)}\n`);
|
|
301
|
+
}
|
|
302
|
+
async function disconnectGitHub(config) {
|
|
303
|
+
await (0, api_1.request)(config, 'DELETE', '/github/disconnect');
|
|
304
|
+
await (0, analytics_1.track)('cli_github_disconnect');
|
|
305
|
+
process.stdout.write('Disconnected from GitHub.\n');
|
|
306
|
+
}
|
|
307
|
+
async function getGitHubStatus(config, json) {
|
|
308
|
+
const connection = await (0, api_1.request)(config, 'GET', '/github/connection');
|
|
309
|
+
if (json) {
|
|
310
|
+
(0, output_1.printJson)(connection);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (!connection.connected) {
|
|
314
|
+
process.stdout.write('Not connected to GitHub.\n');
|
|
315
|
+
process.stdout.write('\nConnect with: orchagent github connect\n');
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
process.stdout.write(`GitHub Status:\n\n`);
|
|
319
|
+
process.stdout.write(` Connected: ${chalk_1.default.green('Yes')}\n`);
|
|
320
|
+
process.stdout.write(` Username: ${chalk_1.default.bold(connection.username)}\n`);
|
|
321
|
+
if (connection.connected_at) {
|
|
322
|
+
const date = new Date(connection.connected_at).toLocaleDateString();
|
|
323
|
+
process.stdout.write(` Since: ${date}\n`);
|
|
324
|
+
}
|
|
325
|
+
if (connection.scopes?.length) {
|
|
326
|
+
process.stdout.write(` Scopes: ${connection.scopes.join(', ')}\n`);
|
|
327
|
+
}
|
|
328
|
+
process.stdout.write('\n');
|
|
329
|
+
}
|
|
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
|
+
async function scanGitHubRepo(config, repo, json) {
|
|
367
|
+
// Parse owner/repo format
|
|
368
|
+
const parts = repo.split('/');
|
|
369
|
+
if (parts.length !== 2) {
|
|
370
|
+
throw new errors_1.CliError(`Invalid repository format: ${repo}\n\n` +
|
|
371
|
+
`Use owner/repo format, e.g.: orchagent github scan myorg/myrepo`);
|
|
372
|
+
}
|
|
373
|
+
const [owner, repoName] = parts;
|
|
374
|
+
const results = await (0, api_1.request)(config, 'GET', `/github/repos/${owner}/${repoName}/scan`);
|
|
375
|
+
await (0, analytics_1.track)('cli_github_scan', { repo, found: results.length });
|
|
376
|
+
if (json) {
|
|
377
|
+
(0, output_1.printJson)(results);
|
|
378
|
+
return results;
|
|
379
|
+
}
|
|
380
|
+
if (results.length === 0) {
|
|
381
|
+
process.stdout.write(`No agents or skills detected in ${repo}.\n`);
|
|
382
|
+
process.stdout.write('\nMake sure your repository contains:\n');
|
|
383
|
+
process.stdout.write(' - An orchagent.yaml or orchagent.json manifest file\n');
|
|
384
|
+
process.stdout.write(' - Or a directory with agent/skill configuration\n');
|
|
385
|
+
return results;
|
|
386
|
+
}
|
|
387
|
+
const table = new cli_table3_1.default({
|
|
388
|
+
head: [
|
|
389
|
+
chalk_1.default.bold('Type'),
|
|
390
|
+
chalk_1.default.bold('Path'),
|
|
391
|
+
chalk_1.default.bold('Name'),
|
|
392
|
+
],
|
|
393
|
+
});
|
|
394
|
+
results.forEach((item) => {
|
|
395
|
+
const typeLabel = item.type === 'skill' ? chalk_1.default.cyan('skill') : chalk_1.default.magenta('agent');
|
|
396
|
+
table.push([typeLabel, item.path, item.name || '-']);
|
|
397
|
+
});
|
|
398
|
+
process.stdout.write(`${table.toString()}\n`);
|
|
399
|
+
process.stdout.write(`\nFound ${results.length} item${results.length === 1 ? '' : 's'} in ${repo}.\n`);
|
|
400
|
+
process.stdout.write(`\nImport with: orchagent github import ${repo} --path <path>\n`);
|
|
401
|
+
return results;
|
|
402
|
+
}
|
|
403
|
+
async function importFromGitHub(config, repo, options) {
|
|
404
|
+
// Parse owner/repo format
|
|
405
|
+
const parts = repo.split('/');
|
|
406
|
+
if (parts.length !== 2) {
|
|
407
|
+
throw new errors_1.CliError(`Invalid repository format: ${repo}\n\n` +
|
|
408
|
+
`Use owner/repo format, e.g.: orchagent github import myorg/myrepo`);
|
|
409
|
+
}
|
|
410
|
+
const [owner, repoName] = parts;
|
|
411
|
+
let selectedPath = options.path;
|
|
412
|
+
// If no path specified, scan first and let user choose
|
|
413
|
+
if (!selectedPath) {
|
|
414
|
+
const results = await scanGitHubRepo(config, repo, false);
|
|
415
|
+
if (results.length === 0) {
|
|
416
|
+
throw new errors_1.CliError(`No importable items found in ${repo}.\n\n` +
|
|
417
|
+
`Make sure your repository contains an orchagent.yaml manifest.`);
|
|
418
|
+
}
|
|
419
|
+
if (results.length === 1) {
|
|
420
|
+
selectedPath = results[0].path;
|
|
421
|
+
process.stdout.write(`\nImporting: ${results[0].path}\n`);
|
|
422
|
+
}
|
|
423
|
+
else {
|
|
424
|
+
const selection = await promptForSelection(results);
|
|
425
|
+
if (!selection) {
|
|
426
|
+
process.stdout.write('Import cancelled.\n');
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
selectedPath = selection.path;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
// Determine visibility (default to public)
|
|
433
|
+
const isPublic = options.private ? false : true;
|
|
434
|
+
const importResult = await (0, api_1.request)(config, 'POST', '/github/import', {
|
|
435
|
+
body: JSON.stringify({
|
|
436
|
+
owner,
|
|
437
|
+
repo: repoName,
|
|
438
|
+
path: selectedPath,
|
|
439
|
+
is_public: isPublic,
|
|
440
|
+
name: options.name,
|
|
441
|
+
}),
|
|
442
|
+
headers: { 'Content-Type': 'application/json' },
|
|
443
|
+
});
|
|
444
|
+
await (0, analytics_1.track)('cli_github_import', {
|
|
445
|
+
repo,
|
|
446
|
+
path: selectedPath,
|
|
447
|
+
is_public: isPublic,
|
|
448
|
+
type: importResult.type,
|
|
449
|
+
});
|
|
450
|
+
if (options.json) {
|
|
451
|
+
(0, output_1.printJson)(importResult);
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
process.stdout.write('\n');
|
|
455
|
+
process.stdout.write(`Imported ${chalk_1.default.bold(importResult.name)} from ${repo}\n`);
|
|
456
|
+
process.stdout.write('\n');
|
|
457
|
+
process.stdout.write(` Agent: ${importResult.org_slug}/${importResult.name}\n`);
|
|
458
|
+
process.stdout.write(` Version: ${importResult.version}\n`);
|
|
459
|
+
process.stdout.write(` Type: ${importResult.type}\n`);
|
|
460
|
+
process.stdout.write(` Public: ${isPublic ? chalk_1.default.green('Yes') : chalk_1.default.yellow('No')}\n`);
|
|
461
|
+
process.stdout.write('\n');
|
|
462
|
+
process.stdout.write(`View at: https://orchagent.io/${importResult.org_slug}/${importResult.name}\n`);
|
|
463
|
+
}
|
|
464
|
+
// Command registration
|
|
465
|
+
function registerGitHubCommand(program) {
|
|
466
|
+
const github = program
|
|
467
|
+
.command('github')
|
|
468
|
+
.description('Connect to GitHub and import agents');
|
|
469
|
+
github
|
|
470
|
+
.command('connect')
|
|
471
|
+
.description('Connect your GitHub account via browser OAuth')
|
|
472
|
+
.option('--port <port>', `Localhost port for callback (default: ${DEFAULT_AUTH_PORT})`, String(DEFAULT_AUTH_PORT))
|
|
473
|
+
.action(async (options) => {
|
|
474
|
+
const config = await (0, config_1.getResolvedConfig)();
|
|
475
|
+
if (!config.apiKey) {
|
|
476
|
+
throw new errors_1.CliError('Missing API key. Run `orchagent login` first.');
|
|
477
|
+
}
|
|
478
|
+
const port = parseInt(options.port || String(DEFAULT_AUTH_PORT), 10);
|
|
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);
|
|
483
|
+
});
|
|
484
|
+
github
|
|
485
|
+
.command('disconnect')
|
|
486
|
+
.description('Remove GitHub connection')
|
|
487
|
+
.action(async () => {
|
|
488
|
+
const config = await (0, config_1.getResolvedConfig)();
|
|
489
|
+
if (!config.apiKey) {
|
|
490
|
+
throw new errors_1.CliError('Missing API key. Run `orchagent login` first.');
|
|
491
|
+
}
|
|
492
|
+
await disconnectGitHub(config);
|
|
493
|
+
});
|
|
494
|
+
github
|
|
495
|
+
.command('status')
|
|
496
|
+
.description('Show GitHub connection status')
|
|
497
|
+
.option('--json', 'Output raw JSON')
|
|
498
|
+
.action(async (options) => {
|
|
499
|
+
const config = await (0, config_1.getResolvedConfig)();
|
|
500
|
+
if (!config.apiKey) {
|
|
501
|
+
throw new errors_1.CliError('Missing API key. Run `orchagent login` first.');
|
|
502
|
+
}
|
|
503
|
+
await getGitHubStatus(config, options.json || false);
|
|
504
|
+
});
|
|
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
|
+
github
|
|
518
|
+
.command('scan <repo>')
|
|
519
|
+
.description('Scan a repository for agents and skills')
|
|
520
|
+
.option('--json', 'Output raw JSON')
|
|
521
|
+
.action(async (repo, options) => {
|
|
522
|
+
const config = await (0, config_1.getResolvedConfig)();
|
|
523
|
+
if (!config.apiKey) {
|
|
524
|
+
throw new errors_1.CliError('Missing API key. Run `orchagent login` first.');
|
|
525
|
+
}
|
|
526
|
+
await scanGitHubRepo(config, repo, options.json || false);
|
|
527
|
+
});
|
|
528
|
+
github
|
|
529
|
+
.command('import <repo>')
|
|
530
|
+
.description('Import an agent or skill from GitHub')
|
|
531
|
+
.option('--path <path>', 'Path to manifest within repo (scans if not specified)')
|
|
532
|
+
.option('--public', 'Make the agent public (default)')
|
|
533
|
+
.option('--private', 'Make the agent private')
|
|
534
|
+
.option('--name <name>', 'Override agent name')
|
|
535
|
+
.option('--json', 'Output raw JSON')
|
|
536
|
+
.action(async (repo, options) => {
|
|
537
|
+
const config = await (0, config_1.getResolvedConfig)();
|
|
538
|
+
if (!config.apiKey) {
|
|
539
|
+
throw new errors_1.CliError('Missing API key. Run `orchagent login` first.');
|
|
540
|
+
}
|
|
541
|
+
await importFromGitHub(config, repo, options);
|
|
542
|
+
});
|
|
543
|
+
}
|
package/dist/commands/index.js
CHANGED
|
@@ -15,6 +15,9 @@ const keys_1 = require("./keys");
|
|
|
15
15
|
const run_1 = require("./run");
|
|
16
16
|
const info_1 = require("./info");
|
|
17
17
|
const skill_1 = require("./skill");
|
|
18
|
+
const delete_1 = require("./delete");
|
|
19
|
+
const github_1 = require("./github");
|
|
20
|
+
const doctor_1 = require("./doctor");
|
|
18
21
|
function registerCommands(program) {
|
|
19
22
|
(0, login_1.registerLoginCommand)(program);
|
|
20
23
|
(0, whoami_1.registerWhoamiCommand)(program);
|
|
@@ -30,4 +33,7 @@ function registerCommands(program) {
|
|
|
30
33
|
(0, llm_config_1.registerLlmConfigCommand)(program);
|
|
31
34
|
(0, keys_1.registerKeysCommand)(program);
|
|
32
35
|
(0, skill_1.registerSkillCommand)(program);
|
|
36
|
+
(0, delete_1.registerDeleteCommand)(program);
|
|
37
|
+
(0, github_1.registerGitHubCommand)(program);
|
|
38
|
+
(0, doctor_1.registerDoctorCommand)(program);
|
|
33
39
|
}
|