@orchagent/cli 0.3.83 → 0.3.85
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/adapters/claude-code.js +4 -8
- package/dist/commands/billing.js +21 -107
- package/dist/commands/github.js +1 -1
- package/dist/commands/info.js +1 -15
- package/dist/commands/init.js +151 -9
- package/dist/commands/install.js +2 -48
- package/dist/commands/logs.js +40 -4
- package/dist/commands/publish.js +98 -15
- package/dist/commands/pull.js +8 -2
- package/dist/commands/run.js +29 -105
- package/dist/commands/schedule.js +29 -2
- package/dist/commands/secrets.js +2 -1
- package/dist/commands/security.js +2 -2
- package/dist/commands/service.js +18 -11
- package/dist/commands/skill.js +8 -63
- package/dist/commands/test.js +1 -1
- package/dist/lib/api.js +0 -12
- package/dist/lib/doctor/checks/environment.js +145 -0
- package/dist/lib/doctor/output.js +1 -1
- package/dist/lib/errors.js +8 -1
- package/dist/lib/spinner.js +5 -0
- package/package.json +3 -2
- package/dist/lib/pricing.js +0 -22
|
@@ -37,13 +37,6 @@ exports.claudeCodeAdapter = {
|
|
|
37
37
|
errors.push('Agent has no prompt content');
|
|
38
38
|
return { canConvert: false, warnings, errors };
|
|
39
39
|
}
|
|
40
|
-
// Warnings for fields that can't be fully mapped
|
|
41
|
-
if (agent.input_schema) {
|
|
42
|
-
warnings.push('input_schema will be described in the prompt body, not enforced');
|
|
43
|
-
}
|
|
44
|
-
if (agent.output_schema) {
|
|
45
|
-
warnings.push('output_schema will be described in the prompt body, not enforced');
|
|
46
|
-
}
|
|
47
40
|
return { canConvert: true, warnings, errors };
|
|
48
41
|
},
|
|
49
42
|
convert(agent) {
|
|
@@ -52,8 +45,11 @@ exports.claudeCodeAdapter = {
|
|
|
52
45
|
const frontmatter = {
|
|
53
46
|
name: normalizedName,
|
|
54
47
|
description: agent.description || `Delegatable agent: ${agent.name}`,
|
|
55
|
-
tools: 'Read, Glob, Grep', // Safe defaults - read-only
|
|
56
48
|
};
|
|
49
|
+
// Only include tools for agent-type (prompt and skill types are single LLM calls)
|
|
50
|
+
if (agent.type === 'agent') {
|
|
51
|
+
frontmatter.tools = 'Read, Glob, Grep'; // Safe defaults - read-only
|
|
52
|
+
}
|
|
57
53
|
// Map model if specified
|
|
58
54
|
if (agent.default_models?.anthropic) {
|
|
59
55
|
const modelAlias = (0, utils_1.mapModelToAlias)(agent.default_models.anthropic);
|
package/dist/commands/billing.js
CHANGED
|
@@ -4,119 +4,33 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.registerBillingCommand = registerBillingCommand;
|
|
7
|
-
const cli_table3_1 = __importDefault(require("cli-table3"));
|
|
8
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
9
7
|
const open_1 = __importDefault(require("open"));
|
|
10
8
|
const config_1 = require("../lib/config");
|
|
11
9
|
const api_1 = require("../lib/api");
|
|
12
|
-
const errors_1 = require("../lib/errors");
|
|
13
|
-
const output_1 = require("../lib/output");
|
|
14
10
|
function registerBillingCommand(program) {
|
|
15
|
-
|
|
11
|
+
program
|
|
16
12
|
.command('billing')
|
|
17
|
-
.description('
|
|
18
|
-
|
|
19
|
-
billing
|
|
20
|
-
.command('balance')
|
|
21
|
-
.description('Show your credit balance and recent transactions')
|
|
22
|
-
.option('--json', 'Output as JSON')
|
|
23
|
-
.action(async (options) => {
|
|
13
|
+
.description('Open billing portal in your browser')
|
|
14
|
+
.action(async () => {
|
|
24
15
|
const resolved = await (0, config_1.getResolvedConfig)();
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
16
|
+
if (!resolved.apiKey) {
|
|
17
|
+
process.stderr.write('Not logged in. Run: orch login\n');
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
// Get the billing portal URL from the gateway
|
|
21
|
+
try {
|
|
22
|
+
const data = await (0, api_1.request)(resolved, 'GET', '/billing/portal');
|
|
23
|
+
process.stdout.write('Opening billing portal...\n');
|
|
24
|
+
await (0, open_1.default)(data.url);
|
|
25
|
+
process.stdout.write(`If browser doesn't open, visit:\n${data.url}\n`);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
// Fallback to direct web URL
|
|
29
|
+
const webUrl = resolved.apiUrl.replace('api.', '').replace('/v1', '');
|
|
30
|
+
const url = `${webUrl}/settings/billing`;
|
|
31
|
+
process.stdout.write('Opening billing page...\n');
|
|
32
|
+
await (0, open_1.default)(url);
|
|
33
|
+
process.stdout.write(`If browser doesn't open, visit:\n${url}\n`);
|
|
29
34
|
}
|
|
30
|
-
// Show balance
|
|
31
|
-
const balance = data.balance_cents / 100;
|
|
32
|
-
process.stdout.write(chalk_1.default.bold(`\nBalance: ${chalk_1.default.green(`$${balance.toFixed(2)} USD`)}\n\n`));
|
|
33
|
-
// Show recent transactions
|
|
34
|
-
if (data.recent_transactions && data.recent_transactions.length > 0) {
|
|
35
|
-
process.stdout.write(chalk_1.default.bold('Recent Transactions:\n'));
|
|
36
|
-
const table = new cli_table3_1.default({
|
|
37
|
-
head: [
|
|
38
|
-
chalk_1.default.bold('Date'),
|
|
39
|
-
chalk_1.default.bold('Type'),
|
|
40
|
-
chalk_1.default.bold('Amount'),
|
|
41
|
-
chalk_1.default.bold('Balance'),
|
|
42
|
-
],
|
|
43
|
-
});
|
|
44
|
-
data.recent_transactions.forEach((tx) => {
|
|
45
|
-
const date = new Date(tx.created_at).toLocaleDateString();
|
|
46
|
-
const amount = (tx.amount_cents / 100).toFixed(2);
|
|
47
|
-
const balance = (tx.balance_after_cents / 100).toFixed(2);
|
|
48
|
-
const amountColor = tx.amount_cents >= 0 ? chalk_1.default.green : chalk_1.default.red;
|
|
49
|
-
table.push([date, tx.transaction_type, amountColor(`$${amount}`), `$${balance}`]);
|
|
50
|
-
});
|
|
51
|
-
process.stdout.write(`${table.toString()}\n\n`);
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
process.stdout.write('No recent transactions\n\n');
|
|
55
|
-
}
|
|
56
|
-
process.stdout.write(chalk_1.default.gray('Add credits: orch billing add 5\n'));
|
|
57
|
-
});
|
|
58
|
-
// orch billing add <amount>
|
|
59
|
-
billing
|
|
60
|
-
.command('add [amount]')
|
|
61
|
-
.description('Add credits via Stripe checkout (minimum $5.00 USD)')
|
|
62
|
-
.action(async (amount) => {
|
|
63
|
-
const resolved = await (0, config_1.getResolvedConfig)();
|
|
64
|
-
// Parse and validate amount
|
|
65
|
-
let amountNum;
|
|
66
|
-
if (!amount) {
|
|
67
|
-
amountNum = 5.00; // Default to $5
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
amountNum = parseFloat(amount);
|
|
71
|
-
if (isNaN(amountNum) || amountNum < 5.00) {
|
|
72
|
-
throw new errors_1.CliError('Amount must be at least $5.00 USD', errors_1.ExitCodes.INVALID_INPUT);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
const amountCents = Math.round(amountNum * 100);
|
|
76
|
-
// Create checkout session
|
|
77
|
-
const checkout = await (0, api_1.createCreditCheckout)(resolved, amountCents);
|
|
78
|
-
// Open in browser
|
|
79
|
-
process.stdout.write(`\nOpening checkout page...\n`);
|
|
80
|
-
process.stdout.write(`Amount: $${amountNum.toFixed(2)} USD\n\n`);
|
|
81
|
-
await (0, open_1.default)(checkout.checkout_url);
|
|
82
|
-
process.stdout.write(chalk_1.default.gray(`If browser doesn't open, visit:\n${checkout.checkout_url}\n`));
|
|
83
|
-
});
|
|
84
|
-
// orch billing history (alias)
|
|
85
|
-
billing
|
|
86
|
-
.command('history')
|
|
87
|
-
.description('Show transaction history (alias for balance)')
|
|
88
|
-
.option('--json', 'Output as JSON')
|
|
89
|
-
.action(async (options) => {
|
|
90
|
-
// Just call balance command
|
|
91
|
-
const resolved = await (0, config_1.getResolvedConfig)();
|
|
92
|
-
const data = await (0, api_1.getCreditsBalance)(resolved);
|
|
93
|
-
if (options.json) {
|
|
94
|
-
(0, output_1.printJson)(data);
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
// Simplified view - just show transactions
|
|
98
|
-
if (data.recent_transactions && data.recent_transactions.length > 0) {
|
|
99
|
-
const table = new cli_table3_1.default({
|
|
100
|
-
head: [
|
|
101
|
-
chalk_1.default.bold('Date'),
|
|
102
|
-
chalk_1.default.bold('Type'),
|
|
103
|
-
chalk_1.default.bold('Amount'),
|
|
104
|
-
chalk_1.default.bold('Balance'),
|
|
105
|
-
],
|
|
106
|
-
});
|
|
107
|
-
data.recent_transactions.forEach((tx) => {
|
|
108
|
-
const date = new Date(tx.created_at).toLocaleDateString();
|
|
109
|
-
const amount = (tx.amount_cents / 100).toFixed(2);
|
|
110
|
-
const balance = (tx.balance_after_cents / 100).toFixed(2);
|
|
111
|
-
const amountColor = tx.amount_cents >= 0 ? chalk_1.default.green : chalk_1.default.red;
|
|
112
|
-
table.push([date, tx.transaction_type, amountColor(`$${amount}`), `$${balance}`]);
|
|
113
|
-
});
|
|
114
|
-
process.stdout.write(`\n${table.toString()}\n\n`);
|
|
115
|
-
}
|
|
116
|
-
else {
|
|
117
|
-
process.stdout.write('\nNo transactions found\n\n');
|
|
118
|
-
}
|
|
119
|
-
const balance = data.balance_cents / 100;
|
|
120
|
-
process.stdout.write(chalk_1.default.gray(`Current balance: $${balance.toFixed(2)} USD\n`));
|
|
121
35
|
});
|
|
122
36
|
}
|
package/dist/commands/github.js
CHANGED
|
@@ -147,7 +147,7 @@ async function getGitHubStatus(config, json) {
|
|
|
147
147
|
}
|
|
148
148
|
process.stdout.write(`GitHub Status:\n\n`);
|
|
149
149
|
process.stdout.write(` Connected: ${chalk_1.default.green('Yes')}\n`);
|
|
150
|
-
process.stdout.write(` Account: ${chalk_1.default.bold(connection.github_account_login)}\n`);
|
|
150
|
+
process.stdout.write(` Account: ${chalk_1.default.bold(connection.github_account_login || 'Unknown')}\n`);
|
|
151
151
|
if (connection.github_account_type) {
|
|
152
152
|
process.stdout.write(` Type: ${connection.github_account_type === 'User' ? 'User' : 'Organization'}\n`);
|
|
153
153
|
}
|
package/dist/commands/info.js
CHANGED
|
@@ -8,7 +8,6 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
8
8
|
const config_1 = require("../lib/config");
|
|
9
9
|
const api_1 = require("../lib/api");
|
|
10
10
|
const agent_ref_1 = require("../lib/agent-ref");
|
|
11
|
-
const pricing_1 = require("../lib/pricing");
|
|
12
11
|
function formatSchema(schema, indent = ' ') {
|
|
13
12
|
const lines = [];
|
|
14
13
|
const props = schema.properties || {};
|
|
@@ -66,8 +65,6 @@ async function getAgentInfo(config, org, agent, version, workspaceId) {
|
|
|
66
65
|
source_url: meta.source_url,
|
|
67
66
|
run_command: meta.run_command,
|
|
68
67
|
url: meta.url,
|
|
69
|
-
pricing_mode: publicMeta.pricing_mode,
|
|
70
|
-
price_per_call_cents: publicMeta.price_per_call_cents,
|
|
71
68
|
};
|
|
72
69
|
}
|
|
73
70
|
catch (err) {
|
|
@@ -111,14 +108,12 @@ async function getAgentInfo(config, org, agent, version, workspaceId) {
|
|
|
111
108
|
source_url: targetAgent.source_url,
|
|
112
109
|
run_command: targetAgent.run_command,
|
|
113
110
|
url: targetAgent.url,
|
|
114
|
-
pricing_mode: targetAgent.pricing_mode,
|
|
115
|
-
price_per_call_cents: targetAgent.price_per_call_cents,
|
|
116
111
|
};
|
|
117
112
|
}
|
|
118
113
|
function registerInfoCommand(program) {
|
|
119
114
|
program
|
|
120
115
|
.command('info <agent>')
|
|
121
|
-
.description('Show agent details including
|
|
116
|
+
.description('Show agent details including inputs and outputs')
|
|
122
117
|
.option('--json', 'Output as JSON')
|
|
123
118
|
.action(async (agentArg, options) => {
|
|
124
119
|
const config = await (0, config_1.getResolvedConfig)();
|
|
@@ -148,15 +143,6 @@ function registerInfoCommand(program) {
|
|
|
148
143
|
process.stdout.write(`Callable: ${chalk_1.default.green('yes')} — other agents can invoke this via the orchagent SDK\n`);
|
|
149
144
|
}
|
|
150
145
|
process.stdout.write(`Providers: ${agentData.supported_providers.join(', ')}\n`);
|
|
151
|
-
// Display pricing information
|
|
152
|
-
const priceStr = (0, pricing_1.formatPrice)(agentData);
|
|
153
|
-
const color = (0, pricing_1.isPaidAgent)(agentData) ? chalk_1.default.yellow : chalk_1.default.green;
|
|
154
|
-
process.stdout.write(`Price: ${color(priceStr)}\n`);
|
|
155
|
-
// If paid, show server-only message for non-owners
|
|
156
|
-
if ((0, pricing_1.isPaidAgent)(agentData)) {
|
|
157
|
-
process.stdout.write(chalk_1.default.gray('Note: Paid agents run on server only (use orch run)\n'));
|
|
158
|
-
process.stdout.write(chalk_1.default.gray(' Owners can still download for development/testing\n'));
|
|
159
|
-
}
|
|
160
146
|
if (agentData.type === 'tool') {
|
|
161
147
|
// Don't show internal routing URLs - they confuse users
|
|
162
148
|
if (agentData.url && !agentData.url.includes('.internal')) {
|
package/dist/commands/init.js
CHANGED
|
@@ -123,6 +123,133 @@ function main() {
|
|
|
123
123
|
|
|
124
124
|
main();
|
|
125
125
|
`;
|
|
126
|
+
const ALWAYS_ON_TEMPLATE_PY = `"""
|
|
127
|
+
orchagent always-on service entrypoint.
|
|
128
|
+
|
|
129
|
+
Runs a long-lived HTTP server that handles requests over HTTP.
|
|
130
|
+
This is the standard pattern for always-on services on orchagent.
|
|
131
|
+
|
|
132
|
+
IMPORTANT: Port 8080 is reserved by the platform health server.
|
|
133
|
+
Use a different port (default: 3000).
|
|
134
|
+
|
|
135
|
+
Local development:
|
|
136
|
+
python main.py
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
import json
|
|
140
|
+
import os
|
|
141
|
+
from http.server import HTTPServer, BaseHTTPRequestHandler
|
|
142
|
+
|
|
143
|
+
PORT = int(os.environ.get("PORT", "3000"))
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class Handler(BaseHTTPRequestHandler):
|
|
147
|
+
def do_POST(self):
|
|
148
|
+
content_length = int(self.headers.get("Content-Length", 0))
|
|
149
|
+
body = self.rfile.read(content_length)
|
|
150
|
+
try:
|
|
151
|
+
data = json.loads(body) if body else {}
|
|
152
|
+
except json.JSONDecodeError:
|
|
153
|
+
self._respond(400, {"error": "Invalid JSON"})
|
|
154
|
+
return
|
|
155
|
+
|
|
156
|
+
user_input = data.get("input", "")
|
|
157
|
+
|
|
158
|
+
# --- Your logic here ---
|
|
159
|
+
# To use workspace secrets, add them to "required_secrets" in orchagent.json:
|
|
160
|
+
# "required_secrets": ["MY_API_KEY"]
|
|
161
|
+
# Then access via: os.environ["MY_API_KEY"]
|
|
162
|
+
result = f"Received: {user_input}"
|
|
163
|
+
# --- End your logic ---
|
|
164
|
+
|
|
165
|
+
self._respond(200, {"result": result})
|
|
166
|
+
|
|
167
|
+
def do_GET(self):
|
|
168
|
+
if self.path == "/health":
|
|
169
|
+
self._respond(200, {"status": "ok"})
|
|
170
|
+
return
|
|
171
|
+
self._respond(200, {"status": "running"})
|
|
172
|
+
|
|
173
|
+
def _respond(self, code, body):
|
|
174
|
+
self.send_response(code)
|
|
175
|
+
self.send_header("Content-Type", "application/json")
|
|
176
|
+
self.end_headers()
|
|
177
|
+
self.wfile.write(json.dumps(body).encode())
|
|
178
|
+
|
|
179
|
+
def log_message(self, format, *args):
|
|
180
|
+
print(f"[{self.log_date_time_string()}] {format % args}")
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
if __name__ == "__main__":
|
|
184
|
+
server = HTTPServer(("0.0.0.0", PORT), Handler)
|
|
185
|
+
print(f"Always-on service listening on port {PORT}")
|
|
186
|
+
server.serve_forever()
|
|
187
|
+
`;
|
|
188
|
+
const ALWAYS_ON_TEMPLATE_JS = `/**
|
|
189
|
+
* orchagent always-on service entrypoint.
|
|
190
|
+
*
|
|
191
|
+
* Runs a long-lived HTTP server that handles requests over HTTP.
|
|
192
|
+
* This is the standard pattern for always-on services on orchagent.
|
|
193
|
+
*
|
|
194
|
+
* IMPORTANT: Port 8080 is reserved by the platform health server.
|
|
195
|
+
* Use a different port (default: 3000).
|
|
196
|
+
*
|
|
197
|
+
* Local development:
|
|
198
|
+
* node main.js
|
|
199
|
+
*/
|
|
200
|
+
|
|
201
|
+
const http = require('http');
|
|
202
|
+
|
|
203
|
+
const PORT = parseInt(process.env.PORT || '3000', 10);
|
|
204
|
+
|
|
205
|
+
const server = http.createServer((req, res) => {
|
|
206
|
+
if (req.method === 'GET') {
|
|
207
|
+
if (req.url === '/health') {
|
|
208
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
209
|
+
res.end(JSON.stringify({ status: 'ok' }));
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
213
|
+
res.end(JSON.stringify({ status: 'running' }));
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (req.method === 'POST') {
|
|
218
|
+
let body = '';
|
|
219
|
+
req.on('data', chunk => { body += chunk; });
|
|
220
|
+
req.on('end', () => {
|
|
221
|
+
let data;
|
|
222
|
+
try {
|
|
223
|
+
data = body ? JSON.parse(body) : {};
|
|
224
|
+
} catch {
|
|
225
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
226
|
+
res.end(JSON.stringify({ error: 'Invalid JSON' }));
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const input = data.input || '';
|
|
231
|
+
|
|
232
|
+
// --- Your logic here ---
|
|
233
|
+
// To use workspace secrets, add them to "required_secrets" in orchagent.json:
|
|
234
|
+
// "required_secrets": ["MY_API_KEY"]
|
|
235
|
+
// Then access via: process.env.MY_API_KEY
|
|
236
|
+
const result = \`Received: \${input}\`;
|
|
237
|
+
// --- End your logic ---
|
|
238
|
+
|
|
239
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
240
|
+
res.end(JSON.stringify({ result }));
|
|
241
|
+
});
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
res.writeHead(405, { 'Content-Type': 'application/json' });
|
|
246
|
+
res.end(JSON.stringify({ error: 'Method not allowed' }));
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
server.listen(PORT, '0.0.0.0', () => {
|
|
250
|
+
console.log(\`Always-on service listening on port \${PORT}\`);
|
|
251
|
+
});
|
|
252
|
+
`;
|
|
126
253
|
const DISCORD_MAIN_JS = `/**
|
|
127
254
|
* Discord bot agent — powered by Claude.
|
|
128
255
|
*
|
|
@@ -266,6 +393,7 @@ DISCORD_CHANNEL_IDS=
|
|
|
266
393
|
# MODEL=claude-sonnet-4-5-20250929
|
|
267
394
|
# MAX_TOKENS=1024
|
|
268
395
|
`;
|
|
396
|
+
const AGENT_BUILDER_HINT = `\n Tip: orch skill install orchagent-public/agent-builder — gives your AI the full platform builder reference\n`;
|
|
269
397
|
function readmeTemplate(agentName, flavor) {
|
|
270
398
|
if (flavor === 'support_agent') {
|
|
271
399
|
return `# ${agentName}
|
|
@@ -852,6 +980,11 @@ function registerInitCommand(program) {
|
|
|
852
980
|
throw new errors_1.CliError('JavaScript agent-type agents are not yet supported. Use --type tool for JavaScript agents.');
|
|
853
981
|
}
|
|
854
982
|
// JS orchestrators are now supported via the orchagent-sdk npm package
|
|
983
|
+
// Block --language for types that don't create runtime files
|
|
984
|
+
if (isJavaScript && (initMode.type === 'prompt' || initMode.type === 'skill')) {
|
|
985
|
+
throw new errors_1.CliError(`The --language flag has no effect for ${initMode.type} types (no runtime files are created). ` +
|
|
986
|
+
'Use --type tool or --type agent to create a project with runtime scaffolding.');
|
|
987
|
+
}
|
|
855
988
|
if (options.template) {
|
|
856
989
|
const template = options.template.trim().toLowerCase();
|
|
857
990
|
const validTemplates = ['support-agent', 'discord', 'discord-js', 'github-weekly-summary'];
|
|
@@ -988,7 +1121,7 @@ function registerInitCommand(program) {
|
|
|
988
1121
|
process.stdout.write(` ${s + 2}. Copy .env.example to .env and add platform tokens\n`);
|
|
989
1122
|
process.stdout.write(` ${s + 3}. Test locally: pip install -r requirements.txt && python main.py\n`);
|
|
990
1123
|
process.stdout.write(` ${s + 4}. Deploy: orch publish && orch service deploy\n`);
|
|
991
|
-
process.stdout.write(
|
|
1124
|
+
process.stdout.write(AGENT_BUILDER_HINT);
|
|
992
1125
|
return;
|
|
993
1126
|
}
|
|
994
1127
|
// Handle github-weekly-summary template separately (own file set + output)
|
|
@@ -1044,7 +1177,7 @@ function registerInitCommand(program) {
|
|
|
1044
1177
|
process.stdout.write(` ${s + 3}. orch run <org>/${agentName} Test it\n`);
|
|
1045
1178
|
process.stdout.write(` ${s + 4}. orch schedule create <org>/${agentName} --cron "0 9 * * 1" Schedule weekly\n`);
|
|
1046
1179
|
process.stdout.write(`\n See README.md for full setup guide.\n`);
|
|
1047
|
-
process.stdout.write(
|
|
1180
|
+
process.stdout.write(AGENT_BUILDER_HINT);
|
|
1048
1181
|
return;
|
|
1049
1182
|
}
|
|
1050
1183
|
// Handle discord-js template separately (JS Discord bot)
|
|
@@ -1094,7 +1227,7 @@ function registerInitCommand(program) {
|
|
|
1094
1227
|
process.stdout.write(` ${stepNum + 2}. Copy .env.example to .env and fill in your tokens\n`);
|
|
1095
1228
|
process.stdout.write(` ${stepNum + 3}. Test locally: npm install && node main.js\n`);
|
|
1096
1229
|
process.stdout.write(` ${stepNum + 4}. Deploy: orch publish\n`);
|
|
1097
|
-
process.stdout.write(
|
|
1230
|
+
process.stdout.write(AGENT_BUILDER_HINT);
|
|
1098
1231
|
return;
|
|
1099
1232
|
}
|
|
1100
1233
|
const manifestPath = path_1.default.join(targetDir, 'orchagent.json');
|
|
@@ -1182,7 +1315,7 @@ function registerInitCommand(program) {
|
|
|
1182
1315
|
}
|
|
1183
1316
|
else if (initMode.flavor === 'code_runtime') {
|
|
1184
1317
|
if (isJavaScript) {
|
|
1185
|
-
await promises_1.default.writeFile(path_1.default.join(targetDir, 'main.js'), CODE_TEMPLATE_JS);
|
|
1318
|
+
await promises_1.default.writeFile(path_1.default.join(targetDir, 'main.js'), runMode === 'always_on' ? ALWAYS_ON_TEMPLATE_JS : CODE_TEMPLATE_JS);
|
|
1186
1319
|
await promises_1.default.writeFile(path_1.default.join(targetDir, 'package.json'), JSON.stringify({
|
|
1187
1320
|
name: agentName,
|
|
1188
1321
|
private: true,
|
|
@@ -1191,7 +1324,7 @@ function registerInitCommand(program) {
|
|
|
1191
1324
|
}, null, 2) + '\n');
|
|
1192
1325
|
}
|
|
1193
1326
|
else {
|
|
1194
|
-
await promises_1.default.writeFile(path_1.default.join(targetDir, 'main.py'), CODE_TEMPLATE_PY);
|
|
1327
|
+
await promises_1.default.writeFile(path_1.default.join(targetDir, 'main.py'), runMode === 'always_on' ? ALWAYS_ON_TEMPLATE_PY : CODE_TEMPLATE_PY);
|
|
1195
1328
|
}
|
|
1196
1329
|
await promises_1.default.writeFile(schemaPath, SCHEMA_TEMPLATE);
|
|
1197
1330
|
}
|
|
@@ -1226,12 +1359,13 @@ function registerInitCommand(program) {
|
|
|
1226
1359
|
process.stdout.write(` ${prefix}.env.example - Environment variables template\n`);
|
|
1227
1360
|
}
|
|
1228
1361
|
else if (initMode.flavor === 'code_runtime') {
|
|
1362
|
+
const entrypointDesc = runMode === 'always_on' ? 'Always-on HTTP server' : 'Agent entrypoint (stdin/stdout JSON)';
|
|
1229
1363
|
if (isJavaScript) {
|
|
1230
|
-
process.stdout.write(` ${prefix}main.js -
|
|
1364
|
+
process.stdout.write(` ${prefix}main.js - ${entrypointDesc}\n`);
|
|
1231
1365
|
process.stdout.write(` ${prefix}package.json - npm dependencies\n`);
|
|
1232
1366
|
}
|
|
1233
1367
|
else {
|
|
1234
|
-
process.stdout.write(` ${prefix}main.py -
|
|
1368
|
+
process.stdout.write(` ${prefix}main.py - ${entrypointDesc}\n`);
|
|
1235
1369
|
}
|
|
1236
1370
|
}
|
|
1237
1371
|
else {
|
|
@@ -1274,7 +1408,15 @@ function registerInitCommand(program) {
|
|
|
1274
1408
|
if (name) {
|
|
1275
1409
|
process.stdout.write(` 1. cd ${name}\n`);
|
|
1276
1410
|
}
|
|
1277
|
-
if (
|
|
1411
|
+
if (runMode === 'always_on') {
|
|
1412
|
+
const mainFile = isJavaScript ? 'main.js' : 'main.py';
|
|
1413
|
+
const testCmd = isJavaScript ? 'node main.js' : 'python main.py';
|
|
1414
|
+
process.stdout.write(` ${stepNum}. Edit ${mainFile} with your service logic\n`);
|
|
1415
|
+
process.stdout.write(` ${stepNum + 1}. Test locally: ${testCmd}\n`);
|
|
1416
|
+
process.stdout.write(` ${stepNum + 2}. Publish: orch publish\n`);
|
|
1417
|
+
process.stdout.write(` ${stepNum + 3}. Deploy: orch service deploy\n`);
|
|
1418
|
+
}
|
|
1419
|
+
else if (isJavaScript) {
|
|
1278
1420
|
process.stdout.write(` ${stepNum}. Edit main.js with your agent logic\n`);
|
|
1279
1421
|
process.stdout.write(` ${stepNum + 1}. Edit schema.json with your input/output schemas\n`);
|
|
1280
1422
|
process.stdout.write(` ${stepNum + 2}. Test: echo '{"input": "test"}' | node main.js\n`);
|
|
@@ -1296,6 +1438,6 @@ function registerInitCommand(program) {
|
|
|
1296
1438
|
process.stdout.write(` ${stepNum + 1}. Edit schema.json with your input/output schemas\n`);
|
|
1297
1439
|
process.stdout.write(` ${stepNum + 2}. Run: orchagent publish\n`);
|
|
1298
1440
|
}
|
|
1299
|
-
process.stdout.write(
|
|
1441
|
+
process.stdout.write(AGENT_BUILDER_HINT);
|
|
1300
1442
|
});
|
|
1301
1443
|
}
|
package/dist/commands/install.js
CHANGED
|
@@ -15,7 +15,6 @@ const adapters_1 = require("../adapters");
|
|
|
15
15
|
const skill_resolve_1 = require("../lib/skill-resolve");
|
|
16
16
|
const installed_1 = require("../lib/installed");
|
|
17
17
|
const agents_md_utils_1 = require("../lib/agents-md-utils");
|
|
18
|
-
const pricing_1 = require("../lib/pricing");
|
|
19
18
|
const DEFAULT_VERSION = 'latest';
|
|
20
19
|
function parseAgentRef(value) {
|
|
21
20
|
const [ref, versionPart] = value.split('@');
|
|
@@ -44,48 +43,6 @@ async function downloadAgentWithFallback(config, org, name, version, workspaceId
|
|
|
44
43
|
throw err;
|
|
45
44
|
}
|
|
46
45
|
}
|
|
47
|
-
// Check if paid agent
|
|
48
|
-
if (publicMeta && (0, pricing_1.isPaidAgent)(publicMeta)) {
|
|
49
|
-
// Paid agent - check if owner
|
|
50
|
-
if (config.apiKey) {
|
|
51
|
-
const callerOrg = await (0, api_1.getOrg)(config, workspaceId);
|
|
52
|
-
const isOwner = (publicMeta.org_id && callerOrg.id === publicMeta.org_id) ||
|
|
53
|
-
(publicMeta.org_slug && callerOrg.slug === publicMeta.org_slug);
|
|
54
|
-
if (isOwner) {
|
|
55
|
-
// Owner - fetch from authenticated endpoint with full prompt
|
|
56
|
-
const myAgents = await (0, api_1.listMyAgents)(config, workspaceId);
|
|
57
|
-
const matching = myAgents.filter(a => a.name === name);
|
|
58
|
-
if (matching.length > 0) {
|
|
59
|
-
let targetAgent;
|
|
60
|
-
if (version === 'latest') {
|
|
61
|
-
targetAgent = matching.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())[0];
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
const found = matching.find(a => a.version === version);
|
|
65
|
-
if (!found) {
|
|
66
|
-
throw new api_1.ApiError(`Agent '${org}/${name}@${version}' not found`, 404);
|
|
67
|
-
}
|
|
68
|
-
targetAgent = found;
|
|
69
|
-
}
|
|
70
|
-
// Fetch full agent data with prompt from authenticated endpoint
|
|
71
|
-
const agentData = await (0, api_1.request)(config, 'GET', `/agents/${targetAgent.id}`);
|
|
72
|
-
return { ...agentData, org_slug: org };
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
// Non-owner - block with helpful message
|
|
77
|
-
const price = (0, pricing_1.formatPrice)(publicMeta);
|
|
78
|
-
throw new errors_1.CliError(`This agent is paid (${price}) and runs on server only.\n\n` +
|
|
79
|
-
`Use: orch run ${org}/${name}@${version} --data '{...}'`);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
// Not authenticated - block
|
|
84
|
-
const price = (0, pricing_1.formatPrice)(publicMeta);
|
|
85
|
-
throw new errors_1.CliError(`This agent is paid (${price}) and runs on server only.\n\n` +
|
|
86
|
-
`Use: orch run ${org}/${name}@${version} --data '{...}'`);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
46
|
// Check if download is disabled (server-only agent)
|
|
90
47
|
if (publicMeta && publicMeta.allow_local_download === false) {
|
|
91
48
|
// Check if owner (can bypass)
|
|
@@ -114,7 +71,8 @@ async function downloadAgentWithFallback(config, org, name, version, workspaceId
|
|
|
114
71
|
}
|
|
115
72
|
}
|
|
116
73
|
}
|
|
117
|
-
|
|
74
|
+
const typeLabel = publicMeta.type || 'agent';
|
|
75
|
+
throw new errors_1.CliError(`This ${typeLabel} is server-only and cannot be downloaded.\n\n` +
|
|
118
76
|
`Use: orch run ${org}/${name}@${version} --data '{...}'`);
|
|
119
77
|
}
|
|
120
78
|
// Free agent - proceed normally with public data
|
|
@@ -159,10 +117,6 @@ function registerInstallCommand(program) {
|
|
|
159
117
|
.option('--global', 'Install to home directory (alias for --scope user)')
|
|
160
118
|
.option('--dry-run', 'Show what would be installed without making changes')
|
|
161
119
|
.option('--json', 'Output result as JSON (for automation/tooling)')
|
|
162
|
-
.addHelpText('after', `
|
|
163
|
-
Note: Paid agents cannot be installed locally - they run on server only.
|
|
164
|
-
Use 'orchagent run' to execute paid agents.
|
|
165
|
-
`)
|
|
166
120
|
.action(async (agentArg, options) => {
|
|
167
121
|
const jsonMode = options.json === true;
|
|
168
122
|
const log = (msg) => { if (!jsonMode)
|
package/dist/commands/logs.js
CHANGED
|
@@ -56,10 +56,14 @@ function formatDuration(ms) {
|
|
|
56
56
|
return `${(ms / 1000).toFixed(1)}s`;
|
|
57
57
|
return `${(ms / 60000).toFixed(1)}m`;
|
|
58
58
|
}
|
|
59
|
-
/** Detect if a string looks like a UUID (run ID) */
|
|
59
|
+
/** Detect if a string looks like a full UUID (run ID) */
|
|
60
60
|
function isUuid(value) {
|
|
61
61
|
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
|
|
62
62
|
}
|
|
63
|
+
/** Detect if a string looks like a short UUID prefix (8+ hex chars) */
|
|
64
|
+
function isShortUuid(value) {
|
|
65
|
+
return /^[0-9a-f]{7,}$/i.test(value) && !value.includes('/');
|
|
66
|
+
}
|
|
63
67
|
// ============================================
|
|
64
68
|
// COMMAND REGISTRATION
|
|
65
69
|
// ============================================
|
|
@@ -77,16 +81,38 @@ function registerLogsCommand(program) {
|
|
|
77
81
|
throw new errors_1.CliError('Missing API key. Run `orch login` first.');
|
|
78
82
|
}
|
|
79
83
|
const workspaceId = await resolveWorkspaceId(config, options.workspace);
|
|
80
|
-
// If target looks like a UUID, show detailed logs for that run
|
|
84
|
+
// If target looks like a UUID (full or short prefix), show detailed logs for that run
|
|
81
85
|
if (target && isUuid(target)) {
|
|
82
86
|
await showRunLogs(config, workspaceId, target, options.json);
|
|
83
87
|
return;
|
|
84
88
|
}
|
|
85
|
-
|
|
86
|
-
|
|
89
|
+
if (target && isShortUuid(target)) {
|
|
90
|
+
// Short UUID prefix — find the matching run from the list
|
|
91
|
+
const fullId = await resolveShortRunId(config, workspaceId, target);
|
|
92
|
+
await showRunLogs(config, workspaceId, fullId, options.json);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
// Otherwise list runs, optionally filtered by agent name.
|
|
96
|
+
// Strip org prefix if provided (e.g. "joe/my-agent" → "my-agent")
|
|
97
|
+
const agentFilter = target?.includes('/') ? target.split('/').pop() : target;
|
|
98
|
+
await listRuns(config, workspaceId, agentFilter, options);
|
|
87
99
|
});
|
|
88
100
|
}
|
|
89
101
|
// ============================================
|
|
102
|
+
// SHORT RUN ID RESOLUTION
|
|
103
|
+
// ============================================
|
|
104
|
+
async function resolveShortRunId(config, workspaceId, shortId) {
|
|
105
|
+
// Server-side prefix matching — searches ALL runs, not just the last 200
|
|
106
|
+
const result = await (0, api_1.request)(config, 'GET', `/workspaces/${workspaceId}/runs?limit=200&run_id_prefix=${encodeURIComponent(shortId)}`);
|
|
107
|
+
if (result.runs.length === 0) {
|
|
108
|
+
throw new errors_1.CliError(`No run found matching '${shortId}'.`);
|
|
109
|
+
}
|
|
110
|
+
if (result.runs.length > 1) {
|
|
111
|
+
throw new errors_1.CliError(`Ambiguous run ID '${shortId}' — matches ${result.runs.length} runs. Use more characters to narrow it down.`);
|
|
112
|
+
}
|
|
113
|
+
return result.runs[0].id;
|
|
114
|
+
}
|
|
115
|
+
// ============================================
|
|
90
116
|
// LIST RUNS
|
|
91
117
|
// ============================================
|
|
92
118
|
async function listRuns(config, workspaceId, agentName, options) {
|
|
@@ -161,6 +187,16 @@ async function showRunLogs(config, workspaceId, runId, json) {
|
|
|
161
187
|
const exitLabel = result.exit_code === 0 ? chalk_1.default.green(String(result.exit_code)) : chalk_1.default.red(String(result.exit_code));
|
|
162
188
|
process.stdout.write(`Exit code: ${exitLabel}\n`);
|
|
163
189
|
}
|
|
190
|
+
// Input data
|
|
191
|
+
if (result.input_data != null && Object.keys(result.input_data).length > 0) {
|
|
192
|
+
process.stdout.write('\n' + chalk_1.default.bold.blue('--- input ---') + '\n' +
|
|
193
|
+
JSON.stringify(result.input_data, null, 2) + '\n');
|
|
194
|
+
}
|
|
195
|
+
// Output data
|
|
196
|
+
if (result.output_data != null && Object.keys(result.output_data).length > 0) {
|
|
197
|
+
process.stdout.write('\n' + chalk_1.default.bold.green('--- output ---') + '\n' +
|
|
198
|
+
JSON.stringify(result.output_data, null, 2) + '\n');
|
|
199
|
+
}
|
|
164
200
|
// Error message
|
|
165
201
|
if (result.error_message) {
|
|
166
202
|
process.stdout.write('\n' + chalk_1.default.red.bold('Error:\n') + chalk_1.default.red(result.error_message) + '\n');
|