@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
package/dist/commands/service.js
CHANGED
|
@@ -60,6 +60,13 @@ function healthColor(health) {
|
|
|
60
60
|
return chalk_1.default.gray(health);
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
|
+
function formatServiceUrl(svc) {
|
|
64
|
+
const url = svc.provider_url || svc.cloud_run_url || '-';
|
|
65
|
+
if (url !== '-' && svc.infrastructure_provider === 'flyio') {
|
|
66
|
+
return `${url} ${chalk_1.default.gray('(internal — not a public endpoint)')}`;
|
|
67
|
+
}
|
|
68
|
+
return url;
|
|
69
|
+
}
|
|
63
70
|
function severityColor(severity, message) {
|
|
64
71
|
switch (severity.toUpperCase()) {
|
|
65
72
|
case 'ERROR':
|
|
@@ -135,7 +142,7 @@ function registerServiceCommand(program) {
|
|
|
135
142
|
match = agentsList.find(a => a.name === agentName && a.version === agentVersion);
|
|
136
143
|
}
|
|
137
144
|
if (!match) {
|
|
138
|
-
spinner.
|
|
145
|
+
spinner.stop();
|
|
139
146
|
throw new errors_1.CliError(`Agent '${agentName}' (version ${agentVersion}) not found in workspace`);
|
|
140
147
|
}
|
|
141
148
|
agentId = match.id;
|
|
@@ -144,7 +151,7 @@ function registerServiceCommand(program) {
|
|
|
144
151
|
catch (e) {
|
|
145
152
|
if (e instanceof errors_1.CliError)
|
|
146
153
|
throw e;
|
|
147
|
-
spinner.
|
|
154
|
+
spinner.stop();
|
|
148
155
|
throw e;
|
|
149
156
|
}
|
|
150
157
|
// C-2: Show deprecation notice when --secret is used
|
|
@@ -184,7 +191,7 @@ function registerServiceCommand(program) {
|
|
|
184
191
|
process.stdout.write(` ${chalk_1.default.bold('Name:')} ${svc.service_name}\n`);
|
|
185
192
|
process.stdout.write(` ${chalk_1.default.bold('Agent:')} ${svc.agent_name}@${svc.agent_version}\n`);
|
|
186
193
|
process.stdout.write(` ${chalk_1.default.bold('State:')} ${stateColor(svc.current_state)}\n`);
|
|
187
|
-
process.stdout.write(` ${chalk_1.default.bold('URL:')} ${svc
|
|
194
|
+
process.stdout.write(` ${chalk_1.default.bold('URL:')} ${formatServiceUrl(svc)}\n`);
|
|
188
195
|
if (options.pin) {
|
|
189
196
|
process.stdout.write(` ${chalk_1.default.bold('Pinned:')} ${chalk_1.default.yellow(`yes (won't auto-update on publish)`)}\n`);
|
|
190
197
|
}
|
|
@@ -192,7 +199,7 @@ function registerServiceCommand(program) {
|
|
|
192
199
|
process.stdout.write(chalk_1.default.gray(`View logs: orch service logs ${svc.id}\n`));
|
|
193
200
|
}
|
|
194
201
|
catch (e) {
|
|
195
|
-
deploySpinner.
|
|
202
|
+
deploySpinner.stop();
|
|
196
203
|
throw e;
|
|
197
204
|
}
|
|
198
205
|
});
|
|
@@ -311,7 +318,7 @@ function registerServiceCommand(program) {
|
|
|
311
318
|
process.stdout.write(`${chalk_1.default.green('\u2713')} Service '${result.service.service_name}' restarted (restarts: ${result.service.restart_count})\n`);
|
|
312
319
|
}
|
|
313
320
|
catch (e) {
|
|
314
|
-
spinner.
|
|
321
|
+
spinner.stop();
|
|
315
322
|
throw e;
|
|
316
323
|
}
|
|
317
324
|
});
|
|
@@ -348,7 +355,7 @@ function registerServiceCommand(program) {
|
|
|
348
355
|
}
|
|
349
356
|
process.stdout.write(` Instances: ${svc.min_instances}-${svc.max_instances}\n`);
|
|
350
357
|
process.stdout.write(` Service ID: ${svc.provider_service_id || svc.cloud_run_service || '-'}\n`);
|
|
351
|
-
process.stdout.write(` URL: ${svc
|
|
358
|
+
process.stdout.write(` URL: ${formatServiceUrl(svc)}\n`);
|
|
352
359
|
process.stdout.write(` Deployed: ${formatDate(svc.last_deployed_at)}\n`);
|
|
353
360
|
process.stdout.write(` Last Restart: ${formatDate(svc.last_restart_at)}\n`);
|
|
354
361
|
if (svc.last_error) {
|
|
@@ -414,7 +421,7 @@ function registerServiceCommand(program) {
|
|
|
414
421
|
process.stdout.write(`${chalk_1.default.green('\u2713')} Service '${result.service.service_name}' deleted\n`);
|
|
415
422
|
}
|
|
416
423
|
catch (e) {
|
|
417
|
-
spinner.
|
|
424
|
+
spinner.stop();
|
|
418
425
|
throw e;
|
|
419
426
|
}
|
|
420
427
|
});
|
|
@@ -468,7 +475,7 @@ function registerServiceCommand(program) {
|
|
|
468
475
|
}
|
|
469
476
|
}
|
|
470
477
|
catch (e) {
|
|
471
|
-
spinner.
|
|
478
|
+
spinner.stop();
|
|
472
479
|
throw e;
|
|
473
480
|
}
|
|
474
481
|
});
|
|
@@ -517,7 +524,7 @@ function registerServiceCommand(program) {
|
|
|
517
524
|
}
|
|
518
525
|
}
|
|
519
526
|
catch (e) {
|
|
520
|
-
spinner.
|
|
527
|
+
spinner.stop();
|
|
521
528
|
throw e;
|
|
522
529
|
}
|
|
523
530
|
});
|
|
@@ -594,7 +601,7 @@ function registerServiceCommand(program) {
|
|
|
594
601
|
}
|
|
595
602
|
}
|
|
596
603
|
catch (e) {
|
|
597
|
-
spinner.
|
|
604
|
+
spinner.stop();
|
|
598
605
|
throw e;
|
|
599
606
|
}
|
|
600
607
|
});
|
|
@@ -638,7 +645,7 @@ function registerServiceCommand(program) {
|
|
|
638
645
|
}
|
|
639
646
|
}
|
|
640
647
|
catch (e) {
|
|
641
|
-
spinner.
|
|
648
|
+
spinner.stop();
|
|
642
649
|
throw e;
|
|
643
650
|
}
|
|
644
651
|
});
|
package/dist/commands/skill.js
CHANGED
|
@@ -45,7 +45,6 @@ const api_1 = require("../lib/api");
|
|
|
45
45
|
const errors_1 = require("../lib/errors");
|
|
46
46
|
const analytics_1 = require("../lib/analytics");
|
|
47
47
|
const installed_1 = require("../lib/installed");
|
|
48
|
-
const pricing_1 = require("../lib/pricing");
|
|
49
48
|
const package_json_1 = __importDefault(require("../../package.json"));
|
|
50
49
|
const DEFAULT_VERSION = 'latest';
|
|
51
50
|
function stripFrontmatter(content) {
|
|
@@ -110,55 +109,6 @@ async function downloadSkillWithFallback(config, org, skill, version, workspaceI
|
|
|
110
109
|
throw new errors_1.CliError(`${org}/${skill} is not a skill (type: ${skillType || 'prompt'})`);
|
|
111
110
|
}
|
|
112
111
|
}
|
|
113
|
-
// Check if paid skill BEFORE attempting download
|
|
114
|
-
if (skillMeta && (0, pricing_1.isPaidAgent)(skillMeta)) {
|
|
115
|
-
// Paid skill - check ownership
|
|
116
|
-
if (config.apiKey) {
|
|
117
|
-
const callerOrg = await (0, api_1.getOrg)(config, workspaceId);
|
|
118
|
-
const isOwner = (skillMeta.org_id && callerOrg.id === skillMeta.org_id) ||
|
|
119
|
-
(skillMeta.org_slug && callerOrg.slug === skillMeta.org_slug);
|
|
120
|
-
if (isOwner) {
|
|
121
|
-
// Owner - fetch from authenticated endpoint with full content
|
|
122
|
-
const myAgents = await (0, api_1.listMyAgents)(config, workspaceId);
|
|
123
|
-
const matching = myAgents.filter(a => a.name === skill && a.type === 'skill');
|
|
124
|
-
if (matching.length > 0) {
|
|
125
|
-
let targetAgent;
|
|
126
|
-
if (version === 'latest') {
|
|
127
|
-
targetAgent = matching.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())[0];
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
const found = matching.find(a => a.version === version);
|
|
131
|
-
if (!found) {
|
|
132
|
-
throw new api_1.ApiError(`Skill '${org}/${skill}@${version}' not found`, 404);
|
|
133
|
-
}
|
|
134
|
-
targetAgent = found;
|
|
135
|
-
}
|
|
136
|
-
// Fetch full skill data with prompt from authenticated endpoint
|
|
137
|
-
const skillData = await (0, api_1.request)(config, 'GET', `/agents/${targetAgent.id}`);
|
|
138
|
-
// Convert Agent to SkillDownload format
|
|
139
|
-
return {
|
|
140
|
-
type: skillData.type,
|
|
141
|
-
name: skillData.name,
|
|
142
|
-
version: skillData.version,
|
|
143
|
-
description: skillData.description,
|
|
144
|
-
prompt: skillData.prompt,
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
else {
|
|
149
|
-
// Non-owner - block with helpful message
|
|
150
|
-
const price = (0, pricing_1.formatPrice)(skillMeta);
|
|
151
|
-
throw new errors_1.CliError(`This skill is paid (${price}) and can only be used on the server.\n\n` +
|
|
152
|
-
`Paid skills are loaded automatically during server execution.`);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
// Not authenticated - block
|
|
157
|
-
const price = (0, pricing_1.formatPrice)(skillMeta);
|
|
158
|
-
throw new errors_1.CliError(`This skill is paid (${price}) and can only be used on the server.\n\n` +
|
|
159
|
-
`Paid skills are loaded automatically during server execution.`);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
112
|
// Check if download is disabled (server-only skill)
|
|
163
113
|
if (skillMeta && skillMeta.allow_local_download === false) {
|
|
164
114
|
if (config.apiKey) {
|
|
@@ -204,11 +154,6 @@ async function downloadSkillWithFallback(config, org, skill, version, workspaceI
|
|
|
204
154
|
// If download fails but metadata exists, it might be a 403 for other reasons
|
|
205
155
|
if (err instanceof api_1.ApiError && err.status === 403) {
|
|
206
156
|
const payload = err.payload;
|
|
207
|
-
if (payload?.error?.code === 'PAID_AGENT_SERVER_ONLY') {
|
|
208
|
-
const price = payload.error.price_per_call_cents || 0;
|
|
209
|
-
throw new errors_1.CliError(`This skill costs $${(price / 100).toFixed(2)}/call and runs on server only.\n\n` +
|
|
210
|
-
`Use: orchagent run ${org}/${skill}@${version} --data '{...}'`);
|
|
211
|
-
}
|
|
212
157
|
if (payload?.error?.code === 'DOWNLOAD_DISABLED') {
|
|
213
158
|
throw new errors_1.CliError(`This skill is server-only and cannot be downloaded.\n\n` +
|
|
214
159
|
`Skills are loaded automatically during server execution via 'orchagent run'.`);
|
|
@@ -259,18 +204,18 @@ async function downloadSkillWithFallback(config, org, skill, version, workspaceI
|
|
|
259
204
|
}
|
|
260
205
|
function registerSkillCommand(program) {
|
|
261
206
|
const skill = program.command('skill').description('Manage and install skills');
|
|
262
|
-
|
|
207
|
+
skill.action(() => { skill.help(); });
|
|
208
|
+
// orch skill list
|
|
263
209
|
skill
|
|
264
210
|
.command('list')
|
|
265
|
-
.description('
|
|
211
|
+
.description('Browse available skills')
|
|
266
212
|
.option('--json', 'Output raw JSON')
|
|
267
213
|
.action(async () => {
|
|
268
|
-
process.stdout.write('
|
|
269
|
-
'
|
|
270
|
-
'
|
|
271
|
-
'
|
|
272
|
-
'
|
|
273
|
-
'View all skills at: https://orchagent.io/explore\n');
|
|
214
|
+
process.stdout.write('Browse and discover skills at: https://orchagent.io/explore\n\n' +
|
|
215
|
+
'Install a skill:\n' +
|
|
216
|
+
' orch skill install <org>/<skill-name>\n\n' +
|
|
217
|
+
'View installed skills:\n' +
|
|
218
|
+
' orch update --check\n');
|
|
274
219
|
process.exit(0);
|
|
275
220
|
});
|
|
276
221
|
// orch skill create [name]
|
package/dist/commands/test.js
CHANGED
|
@@ -514,7 +514,7 @@ async function runPromptFixtureTests(agentDir, fixtures, verbose, config) {
|
|
|
514
514
|
const detected = await (0, llm_1.detectLlmKey)(['any'], config);
|
|
515
515
|
if (!detected) {
|
|
516
516
|
throw new errors_1.CliError('No LLM key found for fixture tests.\n' +
|
|
517
|
-
'Set an environment variable (e.g., OPENAI_API_KEY) or run `
|
|
517
|
+
'Set an environment variable (e.g., OPENAI_API_KEY) or run `orch secrets set <PROVIDER>_API_KEY <key>`');
|
|
518
518
|
}
|
|
519
519
|
const { provider, key, model: serverModel } = detected;
|
|
520
520
|
const model = serverModel ?? (0, llm_1.getDefaultModel)(provider);
|
package/dist/lib/api.js
CHANGED
|
@@ -65,8 +65,6 @@ exports.getEnvironment = getEnvironment;
|
|
|
65
65
|
exports.createEnvironment = createEnvironment;
|
|
66
66
|
exports.deleteEnvironment = deleteEnvironment;
|
|
67
67
|
exports.setWorkspaceDefaultEnvironment = setWorkspaceDefaultEnvironment;
|
|
68
|
-
exports.getCreditsBalance = getCreditsBalance;
|
|
69
|
-
exports.createCreditCheckout = createCreditCheckout;
|
|
70
68
|
exports.listAgentKeys = listAgentKeys;
|
|
71
69
|
exports.createAgentKey = createAgentKey;
|
|
72
70
|
exports.deleteAgentKey = deleteAgentKey;
|
|
@@ -531,16 +529,6 @@ async function setWorkspaceDefaultEnvironment(config, workspaceId, environmentId
|
|
|
531
529
|
headers: { 'Content-Type': 'application/json' },
|
|
532
530
|
});
|
|
533
531
|
}
|
|
534
|
-
// Billing API functions
|
|
535
|
-
async function getCreditsBalance(config) {
|
|
536
|
-
return request(config, 'GET', '/billing/credits');
|
|
537
|
-
}
|
|
538
|
-
async function createCreditCheckout(config, amountCents) {
|
|
539
|
-
return request(config, 'POST', '/billing/add-credits', {
|
|
540
|
-
body: JSON.stringify({ amount_cents: amountCents }),
|
|
541
|
-
headers: { 'Content-Type': 'application/json' },
|
|
542
|
-
});
|
|
543
|
-
}
|
|
544
532
|
async function listAgentKeys(config, agentId) {
|
|
545
533
|
return request(config, 'GET', `/agents/${agentId}/keys`);
|
|
546
534
|
}
|
|
@@ -6,8 +6,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.checkNodeVersion = checkNodeVersion;
|
|
7
7
|
exports.checkCliVersion = checkCliVersion;
|
|
8
8
|
exports.checkGitAvailable = checkGitAvailable;
|
|
9
|
+
exports.checkDualInstallation = checkDualInstallation;
|
|
9
10
|
exports.runEnvironmentChecks = runEnvironmentChecks;
|
|
10
11
|
const child_process_1 = require("child_process");
|
|
12
|
+
const fs_1 = require("fs");
|
|
11
13
|
const package_json_1 = __importDefault(require("../../../../package.json"));
|
|
12
14
|
const update_notifier_1 = require("../../update-notifier");
|
|
13
15
|
const REQUIRED_NODE_MAJOR = 18;
|
|
@@ -142,6 +144,148 @@ async function checkGitAvailable() {
|
|
|
142
144
|
};
|
|
143
145
|
}
|
|
144
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* Find all binary paths for a given command name using `which -a`.
|
|
149
|
+
* Returns an empty array if the command is not found.
|
|
150
|
+
* Note: Uses execSync with a hardcoded binary name — no user input, safe from injection.
|
|
151
|
+
*/
|
|
152
|
+
function findAllBinaryPaths(binaryName) {
|
|
153
|
+
try {
|
|
154
|
+
const output = (0, child_process_1.execSync)(`which -a ${binaryName}`, {
|
|
155
|
+
encoding: 'utf-8',
|
|
156
|
+
timeout: 5000,
|
|
157
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
158
|
+
});
|
|
159
|
+
return output.trim().split('\n').filter(Boolean);
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return [];
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Get the CLI version from a binary path by running it with --version.
|
|
167
|
+
* Uses execFileSync (no shell) to avoid injection via path characters.
|
|
168
|
+
*/
|
|
169
|
+
function getVersionFromBinary(binPath) {
|
|
170
|
+
try {
|
|
171
|
+
const output = (0, child_process_1.execFileSync)(binPath, ['--version'], {
|
|
172
|
+
encoding: 'utf-8',
|
|
173
|
+
timeout: 5000,
|
|
174
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
175
|
+
});
|
|
176
|
+
const match = output.match(/(\d+\.\d+\.\d+)/);
|
|
177
|
+
return match ? match[1] : null;
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Resolve a path through symlinks. Returns the original path if resolution fails.
|
|
185
|
+
*/
|
|
186
|
+
function safeRealpathSync(p) {
|
|
187
|
+
try {
|
|
188
|
+
return (0, fs_1.realpathSync)(p);
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
return p;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Detect multiple CLI installations at different paths/versions (BUG-008).
|
|
196
|
+
*
|
|
197
|
+
* System-level (/usr/local/bin/orchagent) and user-level (~/.npm-global/bin/orch)
|
|
198
|
+
* installs can coexist silently. `npm update -g` updates one but not the other,
|
|
199
|
+
* leaving the user running an outdated version without knowing it.
|
|
200
|
+
*/
|
|
201
|
+
async function checkDualInstallation() {
|
|
202
|
+
// Skip on Windows (which -a not available)
|
|
203
|
+
if (process.platform === 'win32') {
|
|
204
|
+
return {
|
|
205
|
+
category: 'environment',
|
|
206
|
+
name: 'dual_installation',
|
|
207
|
+
status: 'info',
|
|
208
|
+
message: 'Installation path check skipped (Windows)',
|
|
209
|
+
details: { skipped: true, reason: 'Windows not supported' },
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
const binaryNames = ['orch', 'orchagent'];
|
|
214
|
+
const installations = new Map();
|
|
215
|
+
for (const binary of binaryNames) {
|
|
216
|
+
const paths = findAllBinaryPaths(binary);
|
|
217
|
+
for (const binPath of paths) {
|
|
218
|
+
const realPath = safeRealpathSync(binPath);
|
|
219
|
+
// Deduplicate by resolved real path
|
|
220
|
+
if (installations.has(realPath))
|
|
221
|
+
continue;
|
|
222
|
+
const version = getVersionFromBinary(binPath) || 'unknown';
|
|
223
|
+
installations.set(realPath, {
|
|
224
|
+
path: binPath,
|
|
225
|
+
realPath,
|
|
226
|
+
version,
|
|
227
|
+
binary,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (installations.size <= 1) {
|
|
232
|
+
return {
|
|
233
|
+
category: 'environment',
|
|
234
|
+
name: 'dual_installation',
|
|
235
|
+
status: 'success',
|
|
236
|
+
message: 'Single CLI installation',
|
|
237
|
+
details: {
|
|
238
|
+
installationCount: installations.size,
|
|
239
|
+
installations: [...installations.values()],
|
|
240
|
+
},
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
// Multiple installations found
|
|
244
|
+
const allInstalls = [...installations.values()];
|
|
245
|
+
const versions = new Set(allInstalls.map((i) => i.version));
|
|
246
|
+
const versionsDiffer = versions.size > 1;
|
|
247
|
+
const pathList = allInstalls
|
|
248
|
+
.map((i) => `${i.path} (v${i.version})`)
|
|
249
|
+
.join(', ');
|
|
250
|
+
if (versionsDiffer) {
|
|
251
|
+
return {
|
|
252
|
+
category: 'environment',
|
|
253
|
+
name: 'dual_installation',
|
|
254
|
+
status: 'warning',
|
|
255
|
+
message: `Multiple CLI versions found: ${pathList}`,
|
|
256
|
+
fix: 'Remove the outdated installation. Run `which -a orch orchagent` to see all paths, then remove the older binary',
|
|
257
|
+
details: {
|
|
258
|
+
installationCount: installations.size,
|
|
259
|
+
versionMismatch: true,
|
|
260
|
+
installations: allInstalls,
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
// Same version at multiple paths — informational only
|
|
265
|
+
return {
|
|
266
|
+
category: 'environment',
|
|
267
|
+
name: 'dual_installation',
|
|
268
|
+
status: 'info',
|
|
269
|
+
message: `Multiple CLI paths (same version v${allInstalls[0].version}): ${pathList}`,
|
|
270
|
+
details: {
|
|
271
|
+
installationCount: installations.size,
|
|
272
|
+
versionMismatch: false,
|
|
273
|
+
installations: allInstalls,
|
|
274
|
+
},
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
return {
|
|
279
|
+
category: 'environment',
|
|
280
|
+
name: 'dual_installation',
|
|
281
|
+
status: 'info',
|
|
282
|
+
message: 'Could not check for duplicate installations',
|
|
283
|
+
details: {
|
|
284
|
+
error: err instanceof Error ? err.message : 'unknown error',
|
|
285
|
+
},
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
}
|
|
145
289
|
/**
|
|
146
290
|
* Run all environment checks.
|
|
147
291
|
*/
|
|
@@ -150,6 +294,7 @@ async function runEnvironmentChecks() {
|
|
|
150
294
|
checkNodeVersion(),
|
|
151
295
|
checkCliVersion(),
|
|
152
296
|
checkGitAvailable(),
|
|
297
|
+
checkDualInstallation(),
|
|
153
298
|
]);
|
|
154
299
|
return results;
|
|
155
300
|
}
|
|
@@ -54,7 +54,7 @@ function renderLlmSection(checks, verbose) {
|
|
|
54
54
|
// Build location text
|
|
55
55
|
let location;
|
|
56
56
|
if (serverVal === null) {
|
|
57
|
-
location = localVal ? '
|
|
57
|
+
location = localVal ? 'Local configured (vault keys not checked)' : 'Not configured locally (vault keys used for cloud runs)';
|
|
58
58
|
}
|
|
59
59
|
else if (serverVal && localVal) {
|
|
60
60
|
location = 'Configured (server + local)';
|
package/dist/lib/errors.js
CHANGED
|
@@ -45,6 +45,8 @@ class CliError extends Error {
|
|
|
45
45
|
exitCode;
|
|
46
46
|
cause;
|
|
47
47
|
responseBody;
|
|
48
|
+
/** When true, exitWithError skips printing — the message was already shown (e.g. via spinner.fail). */
|
|
49
|
+
displayed;
|
|
48
50
|
constructor(message, exitCode = 1) {
|
|
49
51
|
super(message);
|
|
50
52
|
this.exitCode = exitCode;
|
|
@@ -78,7 +80,12 @@ async function exitWithError(err) {
|
|
|
78
80
|
}
|
|
79
81
|
// Flush PostHog before exiting
|
|
80
82
|
await (0, analytics_1.shutdownPostHog)();
|
|
81
|
-
|
|
83
|
+
// Skip printing if the error was already shown (e.g. by spinner.fail)
|
|
84
|
+
const alreadyDisplayed = (err instanceof CliError && err.displayed) ||
|
|
85
|
+
(err instanceof Error && err._displayed);
|
|
86
|
+
if (!alreadyDisplayed) {
|
|
87
|
+
process.stderr.write(`${message}\n`);
|
|
88
|
+
}
|
|
82
89
|
if (err instanceof CliError) {
|
|
83
90
|
process.exit(err.exitCode);
|
|
84
91
|
}
|
package/dist/lib/spinner.js
CHANGED
|
@@ -96,6 +96,11 @@ async function withSpinner(text, fn, options) {
|
|
|
96
96
|
? options.failText(err)
|
|
97
97
|
: options?.failText || (err instanceof Error ? err.message : 'Failed');
|
|
98
98
|
spinner.fail(failMsg);
|
|
99
|
+
// Mark as already displayed so exitWithError doesn't print again
|
|
100
|
+
if (err instanceof Error) {
|
|
101
|
+
;
|
|
102
|
+
err._displayed = true;
|
|
103
|
+
}
|
|
99
104
|
throw err;
|
|
100
105
|
}
|
|
101
106
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orchagent/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.85",
|
|
4
4
|
"description": "Command-line interface for orchagent — deploy and run AI agents for your team",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "orchagent <hello@orchagent.io>",
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
"node": ">=18"
|
|
26
26
|
},
|
|
27
27
|
"bin": {
|
|
28
|
-
"orch": "dist/index.js"
|
|
28
|
+
"orch": "dist/index.js",
|
|
29
|
+
"orchagent": "dist/index.js"
|
|
29
30
|
},
|
|
30
31
|
"files": [
|
|
31
32
|
"dist",
|
package/dist/lib/pricing.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isPaidAgent = isPaidAgent;
|
|
4
|
-
exports.formatPrice = formatPrice;
|
|
5
|
-
function isPaidAgent(agent) {
|
|
6
|
-
// Fail-closed: per_call mode with missing or >0 price is paid
|
|
7
|
-
if (agent.pricing_mode === 'per_call') {
|
|
8
|
-
const price = agent.price_per_call_cents;
|
|
9
|
-
return price === null || price === undefined || price > 0;
|
|
10
|
-
}
|
|
11
|
-
return false;
|
|
12
|
-
}
|
|
13
|
-
function formatPrice(agent) {
|
|
14
|
-
if (!isPaidAgent(agent)) {
|
|
15
|
-
return 'FREE';
|
|
16
|
-
}
|
|
17
|
-
const price = agent.price_per_call_cents;
|
|
18
|
-
if (!price) {
|
|
19
|
-
return 'PAID (server-only)'; // Fail-closed message
|
|
20
|
-
}
|
|
21
|
-
return `$${(price / 100).toFixed(2)}/call`;
|
|
22
|
-
}
|