@orchagent/cli 0.3.31 → 0.3.34
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/agents-md.js +14 -1
- package/dist/adapters/claude-code.js +11 -0
- package/dist/adapters/cursor.js +13 -1
- package/dist/commands/call.js +105 -16
- package/dist/commands/config.js +25 -1
- package/dist/commands/delete.js +11 -20
- package/dist/commands/init.js +139 -22
- package/dist/commands/install.js +16 -3
- package/dist/commands/publish.js +76 -1
- package/dist/commands/search.js +52 -22
- package/dist/commands/security.js +2 -2
- package/dist/commands/skill.js +10 -7
- package/dist/commands/star.js +10 -3
- package/dist/commands/update.js +101 -66
- package/dist/commands/whoami.js +18 -0
- package/dist/index.js +6 -1
- package/dist/lib/api.js +71 -3
- package/dist/lib/config.js +11 -0
- package/dist/lib/doctor/checks/llm.js +128 -106
- package/dist/lib/doctor/output.js +91 -13
- package/dist/lib/doctor/runner.js +3 -12
- package/dist/lib/output.js +19 -12
- package/dist/lib/skill-resolve.js +99 -0
- package/dist/lib/update-notifier.js +146 -0
- package/package.json +1 -1
package/dist/commands/install.js
CHANGED
|
@@ -12,6 +12,7 @@ const api_1 = require("../lib/api");
|
|
|
12
12
|
const errors_1 = require("../lib/errors");
|
|
13
13
|
const analytics_1 = require("../lib/analytics");
|
|
14
14
|
const adapters_1 = require("../adapters");
|
|
15
|
+
const skill_resolve_1 = require("../lib/skill-resolve");
|
|
15
16
|
const installed_1 = require("../lib/installed");
|
|
16
17
|
const agents_md_utils_1 = require("../lib/agents-md-utils");
|
|
17
18
|
const pricing_1 = require("../lib/pricing");
|
|
@@ -123,7 +124,7 @@ function registerInstallCommand(program) {
|
|
|
123
124
|
.command('install <agent>')
|
|
124
125
|
.description('Install agent as sub-agent (Claude Code, Cursor, etc.)')
|
|
125
126
|
.option('--format <formats>', 'Comma-separated format IDs (e.g., claude-code,cursor)')
|
|
126
|
-
.option('--scope <scope>', 'Install scope: user (home dir) or project (current dir)'
|
|
127
|
+
.option('--scope <scope>', 'Install scope: user (home dir) or project (current dir)')
|
|
127
128
|
.option('--dry-run', 'Show what would be installed without making changes')
|
|
128
129
|
.option('--json', 'Output result as JSON (for automation/tooling)')
|
|
129
130
|
.addHelpText('after', `
|
|
@@ -187,8 +188,8 @@ Note: Paid agents cannot be installed locally - they run on server only.
|
|
|
187
188
|
}
|
|
188
189
|
}
|
|
189
190
|
result.formats = targetFormats;
|
|
190
|
-
//
|
|
191
|
-
let scope = options.scope;
|
|
191
|
+
// Resolve scope: CLI flag > config default > fallback to 'user'
|
|
192
|
+
let scope = (options.scope ?? await (0, config_1.getDefaultScope)() ?? 'user');
|
|
192
193
|
if (scope !== 'user' && scope !== 'project') {
|
|
193
194
|
const errMsg = 'Scope must be "user" or "project"';
|
|
194
195
|
if (jsonMode) {
|
|
@@ -213,6 +214,18 @@ Note: Paid agents cannot be installed locally - they run on server only.
|
|
|
213
214
|
}
|
|
214
215
|
throw err;
|
|
215
216
|
}
|
|
217
|
+
// Resolve default skills if present
|
|
218
|
+
if (agent.default_skills && agent.default_skills.length > 0) {
|
|
219
|
+
log(`Resolving ${agent.default_skills.length} bundled skill(s)...\n`);
|
|
220
|
+
const skills = await (0, skill_resolve_1.resolveSkills)(resolved, agent.default_skills, (warning) => {
|
|
221
|
+
result.warnings.push(warning);
|
|
222
|
+
logErr(`Warning: ${warning}\n`);
|
|
223
|
+
});
|
|
224
|
+
if (skills.length > 0) {
|
|
225
|
+
agent.resolvedSkills = skills;
|
|
226
|
+
log(`Bundled ${skills.length} skill(s): ${skills.map(s => s.name).join(', ')}\n`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
216
229
|
// Install for each format
|
|
217
230
|
let filesWritten = 0;
|
|
218
231
|
for (const formatId of targetFormats) {
|
package/dist/commands/publish.js
CHANGED
|
@@ -3,6 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.extractTemplateVariables = extractTemplateVariables;
|
|
7
|
+
exports.deriveInputSchema = deriveInputSchema;
|
|
6
8
|
exports.registerPublishCommand = registerPublishCommand;
|
|
7
9
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
8
10
|
const path_1 = __importDefault(require("path"));
|
|
@@ -14,6 +16,44 @@ const api_1 = require("../lib/api");
|
|
|
14
16
|
const errors_1 = require("../lib/errors");
|
|
15
17
|
const analytics_1 = require("../lib/analytics");
|
|
16
18
|
const bundle_1 = require("../lib/bundle");
|
|
19
|
+
/**
|
|
20
|
+
* Extract template placeholders from a prompt template.
|
|
21
|
+
* Matches double-brace patterns like {{variable}}.
|
|
22
|
+
* Returns unique variable names in order of first appearance.
|
|
23
|
+
*/
|
|
24
|
+
function extractTemplateVariables(template) {
|
|
25
|
+
const seen = new Set();
|
|
26
|
+
const result = [];
|
|
27
|
+
// Match double-brace template variables: two opening braces, word chars, two closing braces
|
|
28
|
+
const pattern = /\{\{(\w+)\}\}/g;
|
|
29
|
+
let match;
|
|
30
|
+
while ((match = pattern.exec(template)) !== null) {
|
|
31
|
+
const name = match[1];
|
|
32
|
+
if (!seen.has(name)) {
|
|
33
|
+
seen.add(name);
|
|
34
|
+
result.push(name);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Derive a JSON Schema input object from template variable names.
|
|
41
|
+
* Each variable becomes a required string property.
|
|
42
|
+
*/
|
|
43
|
+
function deriveInputSchema(variables) {
|
|
44
|
+
const properties = {};
|
|
45
|
+
for (const name of variables) {
|
|
46
|
+
properties[name] = {
|
|
47
|
+
type: 'string',
|
|
48
|
+
description: `Value for the ${name} template variable`,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
type: 'object',
|
|
53
|
+
properties,
|
|
54
|
+
required: [...variables],
|
|
55
|
+
};
|
|
56
|
+
}
|
|
17
57
|
/**
|
|
18
58
|
* Handle security flagged error response (422 with error: 'content_flagged')
|
|
19
59
|
* Returns true if the error was handled, false otherwise
|
|
@@ -273,6 +313,7 @@ function registerPublishCommand(program) {
|
|
|
273
313
|
const price = parseFloat(options.price);
|
|
274
314
|
process.stdout.write(`Pricing: $${price.toFixed(2)} USD per call\n`);
|
|
275
315
|
}
|
|
316
|
+
process.stdout.write(`\nView analytics and usage: https://orchagent.io/dashboard\n`);
|
|
276
317
|
}
|
|
277
318
|
catch (err) {
|
|
278
319
|
if (handleSecurityFlaggedError(err)) {
|
|
@@ -338,12 +379,14 @@ function registerPublishCommand(program) {
|
|
|
338
379
|
// Read schemas
|
|
339
380
|
let inputSchema;
|
|
340
381
|
let outputSchema;
|
|
382
|
+
let schemaFromFile = false;
|
|
341
383
|
const schemaPath = path_1.default.join(cwd, 'schema.json');
|
|
342
384
|
try {
|
|
343
385
|
const raw = await promises_1.default.readFile(schemaPath, 'utf-8');
|
|
344
386
|
const schemas = JSON.parse(raw);
|
|
345
387
|
inputSchema = schemas.input;
|
|
346
388
|
outputSchema = schemas.output;
|
|
389
|
+
schemaFromFile = true;
|
|
347
390
|
}
|
|
348
391
|
catch (err) {
|
|
349
392
|
// Schema is optional
|
|
@@ -351,6 +394,33 @@ function registerPublishCommand(program) {
|
|
|
351
394
|
throw new errors_1.CliError(`Failed to read schema.json: ${err}`);
|
|
352
395
|
}
|
|
353
396
|
}
|
|
397
|
+
// For prompt agents, derive input schema from template variables if needed
|
|
398
|
+
if (prompt && (manifest.type === 'prompt' || manifest.type === 'skill')) {
|
|
399
|
+
const templateVars = extractTemplateVariables(prompt);
|
|
400
|
+
if (templateVars.length > 0) {
|
|
401
|
+
if (!schemaFromFile) {
|
|
402
|
+
// No schema.json provided - auto-generate from template variables
|
|
403
|
+
inputSchema = deriveInputSchema(templateVars);
|
|
404
|
+
}
|
|
405
|
+
else if (inputSchema && 'properties' in inputSchema) {
|
|
406
|
+
// schema.json exists - check for mismatches with template variables
|
|
407
|
+
const schemaProps = Object.keys(inputSchema.properties || {});
|
|
408
|
+
const missing = templateVars.filter(v => !schemaProps.includes(v));
|
|
409
|
+
const extra = schemaProps.filter(p => !templateVars.includes(p));
|
|
410
|
+
if (missing.length > 0 || extra.length > 0) {
|
|
411
|
+
const parts = [];
|
|
412
|
+
if (missing.length > 0) {
|
|
413
|
+
parts.push(`template uses {{${missing.join('}}, {{')}}} but schema.json doesn't define ${missing.join(', ')}`);
|
|
414
|
+
}
|
|
415
|
+
if (extra.length > 0) {
|
|
416
|
+
parts.push(`schema.json defines ${extra.join(', ')} but template doesn't use {{${extra.join('}}, {{')}}}`);
|
|
417
|
+
}
|
|
418
|
+
process.stderr.write(chalk_1.default.yellow(`Warning: Schema mismatch - ${parts.join('; ')}.\n`));
|
|
419
|
+
process.stderr.write(chalk_1.default.yellow(` Consider updating schema.json to match your prompt.md template variables.\n`));
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
354
424
|
// For code-based agents, either --url is required OR we bundle the code
|
|
355
425
|
let agentUrl = options.url;
|
|
356
426
|
let shouldUploadBundle = false;
|
|
@@ -393,10 +463,14 @@ function registerPublishCommand(program) {
|
|
|
393
463
|
// Prompt agent validations
|
|
394
464
|
const promptBytes = prompt ? Buffer.byteLength(prompt, 'utf-8') : 0;
|
|
395
465
|
process.stderr.write(` ✓ prompt.md found (${promptBytes.toLocaleString()} bytes)\n`);
|
|
396
|
-
if (
|
|
466
|
+
if (schemaFromFile) {
|
|
397
467
|
const schemaTypes = [inputSchema ? 'input' : null, outputSchema ? 'output' : null].filter(Boolean).join(' + ');
|
|
398
468
|
process.stderr.write(` ✓ schema.json found (${schemaTypes} schemas)\n`);
|
|
399
469
|
}
|
|
470
|
+
else if (inputSchema) {
|
|
471
|
+
const vars = prompt ? extractTemplateVariables(prompt) : [];
|
|
472
|
+
process.stderr.write(` ✓ Input schema derived from template variables: ${vars.join(', ')}\n`);
|
|
473
|
+
}
|
|
400
474
|
}
|
|
401
475
|
else if (manifest.type === 'code') {
|
|
402
476
|
// Code agent validations
|
|
@@ -583,5 +657,6 @@ function registerPublishCommand(program) {
|
|
|
583
657
|
if (shouldUploadBundle) {
|
|
584
658
|
process.stdout.write(`\nNote: Hosted code execution is in beta. Contact support for full deployment.\n`);
|
|
585
659
|
}
|
|
660
|
+
process.stdout.write(`\nView analytics and usage: https://orchagent.io/dashboard\n`);
|
|
586
661
|
});
|
|
587
662
|
}
|
package/dist/commands/search.js
CHANGED
|
@@ -14,7 +14,9 @@ function registerSearchCommand(program) {
|
|
|
14
14
|
.argument('[query]', 'Search query (required unless using --popular or --recent)')
|
|
15
15
|
.option('--popular', 'Show top agents/skills by stars')
|
|
16
16
|
.option('--recent', 'Show most recently published')
|
|
17
|
-
.option('--
|
|
17
|
+
.option('--mine', 'Show only your own agents (including private)')
|
|
18
|
+
.option('--type <type>', 'Filter by type: agents, skills, code, prompt, skill, all (default: all)', 'all')
|
|
19
|
+
.option('--tags <tags>', 'Filter by tags (comma-separated, e.g., security,devops)')
|
|
18
20
|
.option('--limit <n>', `Max results (default: ${DEFAULT_LIMIT})`, String(DEFAULT_LIMIT))
|
|
19
21
|
.option('--free', 'Show only free agents')
|
|
20
22
|
.option('--paid', 'Show only paid agents')
|
|
@@ -23,29 +25,44 @@ function registerSearchCommand(program) {
|
|
|
23
25
|
Pricing Filters:
|
|
24
26
|
--free Show only free agents
|
|
25
27
|
--paid Show only paid agents
|
|
28
|
+
|
|
29
|
+
Tag Filters:
|
|
30
|
+
--tags security,devops Show agents matching any of these tags
|
|
31
|
+
|
|
32
|
+
Ownership Filters:
|
|
33
|
+
--mine Show your own agents (public and private). Requires login.
|
|
26
34
|
`)
|
|
27
35
|
.action(async (query, options) => {
|
|
28
36
|
const config = await (0, config_1.getResolvedConfig)();
|
|
29
37
|
const limit = parseInt(options.limit, 10) || DEFAULT_LIMIT;
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
38
|
+
// Map type filter for API (null means no filter)
|
|
39
|
+
const typeFilter = options.type === 'all' ? undefined : options.type;
|
|
40
|
+
const sort = options.popular ? 'stars' : options.recent ? 'recent' : undefined;
|
|
41
|
+
const tags = options.tags ? options.tags.split(',').map(t => t.trim()).filter(Boolean) : undefined;
|
|
34
42
|
let agents;
|
|
35
|
-
if (
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
if (options.mine) {
|
|
44
|
+
// --mine: search within user's own agents (public + private)
|
|
45
|
+
if (!config.apiKey) {
|
|
46
|
+
process.stderr.write('Error: --mine requires authentication. Run `orchagent login` first.\n');
|
|
47
|
+
process.exitCode = 1;
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
agents = await (0, api_1.searchMyAgents)(config, query, { sort, type: typeFilter });
|
|
51
|
+
await (0, analytics_1.track)('cli_search', { query, type: options.type, mine: true });
|
|
38
52
|
}
|
|
39
53
|
else {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
54
|
+
// Default to popular when no args
|
|
55
|
+
if (!query && !options.popular && !options.recent) {
|
|
56
|
+
options.popular = true;
|
|
57
|
+
}
|
|
58
|
+
if (query) {
|
|
59
|
+
agents = await (0, api_1.searchAgents)(config, query, { sort, tags, type: typeFilter });
|
|
60
|
+
await (0, analytics_1.track)('cli_search', { query, type: options.type, tags: options.tags });
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
agents = await (0, api_1.listPublicAgents)(config, { sort, tags, type: typeFilter });
|
|
64
|
+
await (0, analytics_1.track)('cli_search', { mode: options.popular ? 'popular' : 'recent', type: options.type, tags: options.tags });
|
|
65
|
+
}
|
|
49
66
|
}
|
|
50
67
|
// Filter by pricing if requested
|
|
51
68
|
if (options.free) {
|
|
@@ -55,7 +72,7 @@ Pricing Filters:
|
|
|
55
72
|
agents = agents.filter(a => (0, pricing_1.isPaidAgent)(a));
|
|
56
73
|
}
|
|
57
74
|
// Sort results
|
|
58
|
-
if (options.popular || (!query && !options.recent)) {
|
|
75
|
+
if (options.popular || (!query && !options.recent && !options.mine)) {
|
|
59
76
|
agents.sort((a, b) => (b.stars_count ?? 0) - (a.stars_count ?? 0));
|
|
60
77
|
}
|
|
61
78
|
else if (options.recent) {
|
|
@@ -68,14 +85,27 @@ Pricing Filters:
|
|
|
68
85
|
return;
|
|
69
86
|
}
|
|
70
87
|
if (agents.length === 0) {
|
|
71
|
-
|
|
72
|
-
|
|
88
|
+
if (options.mine) {
|
|
89
|
+
process.stdout.write(query
|
|
90
|
+
? `No agents found matching "${query}" in your account.\n`
|
|
91
|
+
: 'You have no published agents yet.\n');
|
|
92
|
+
process.stdout.write('\nTip: Run "orchagent init" to create your first agent.\n');
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
process.stdout.write(query ? 'No results found matching your search.\n' : 'No public agents found.\n');
|
|
96
|
+
process.stdout.write('\nBrowse all agents at: https://orchagent.io/explore\n');
|
|
97
|
+
}
|
|
73
98
|
return;
|
|
74
99
|
}
|
|
75
|
-
(0, output_1.printAgentsTable)(agents);
|
|
100
|
+
(0, output_1.printAgentsTable)(agents, { showVisibility: options.mine });
|
|
76
101
|
if (agents.length === limit) {
|
|
77
102
|
process.stdout.write(`\nShowing top ${limit} results. Use --limit <n> for more.\n`);
|
|
78
103
|
}
|
|
79
|
-
|
|
104
|
+
if (options.mine) {
|
|
105
|
+
process.stdout.write('\nTip: Run "orchagent info <agent>" to see details, or "orchagent delete <agent>" to remove.\n');
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
process.stdout.write('\nTip: Run "orchagent info <agent>" to see input schema and details.\n');
|
|
109
|
+
}
|
|
80
110
|
});
|
|
81
111
|
}
|
|
@@ -67,7 +67,7 @@ function formatSummaryOutput(result) {
|
|
|
67
67
|
process.stdout.write('━'.repeat(50) + '\n\n');
|
|
68
68
|
// Agent info
|
|
69
69
|
process.stdout.write(`${chalk_1.default.bold('Agent:')} ${result.agent_id}\n`);
|
|
70
|
-
process.stdout.write(`${chalk_1.default.bold('Scan Time:')} ${result.
|
|
70
|
+
process.stdout.write(`${chalk_1.default.bold('Scan Time:')} ${result.scanned_at}\n\n`);
|
|
71
71
|
// Risk level banner
|
|
72
72
|
process.stdout.write(`${chalk_1.default.bold('Risk Level:')} ${riskLevelColor(result.risk_level)}\n\n`);
|
|
73
73
|
// Summary stats
|
|
@@ -282,7 +282,7 @@ function generateMarkdownReport(result) {
|
|
|
282
282
|
lines.push('# Security Scan Report');
|
|
283
283
|
lines.push('');
|
|
284
284
|
lines.push(`**Agent:** ${result.agent_id}`);
|
|
285
|
-
lines.push(`**Scan Time:** ${result.
|
|
285
|
+
lines.push(`**Scan Time:** ${result.scanned_at}`);
|
|
286
286
|
lines.push(`**Risk Level:** ${result.risk_level.toUpperCase()}`);
|
|
287
287
|
lines.push('');
|
|
288
288
|
lines.push('## Summary');
|
package/dist/commands/skill.js
CHANGED
|
@@ -269,7 +269,7 @@ Instructions and guidance for AI agents...
|
|
|
269
269
|
.command('install <skill>')
|
|
270
270
|
.description('Install skill to local AI tool directories (Claude Code, Cursor, etc.)')
|
|
271
271
|
.option('--global', 'Install to home directory (default: current directory)')
|
|
272
|
-
.option('--scope <scope>', 'Install scope: user or project'
|
|
272
|
+
.option('--scope <scope>', 'Install scope: user or project')
|
|
273
273
|
.option('--dry-run', 'Show what would be installed without making changes')
|
|
274
274
|
.option('--format <formats>', 'Comma-separated format IDs (e.g., claude-code,cursor)')
|
|
275
275
|
.option('--all-formats', 'Install to all supported AI tool directories')
|
|
@@ -401,8 +401,8 @@ Instructions and guidance for AI agents...
|
|
|
401
401
|
'The skill exists but has an empty prompt. This may be a publishing issue.\n' +
|
|
402
402
|
'Try re-publishing the skill or contact the skill author.');
|
|
403
403
|
}
|
|
404
|
-
// Determine scope (--global is legacy alias for --scope user)
|
|
405
|
-
const scope = options.global ? 'user' : (options.scope || 'project');
|
|
404
|
+
// Determine scope (--global is legacy alias for --scope user; then config default; then 'project')
|
|
405
|
+
const scope = options.global ? 'user' : (options.scope || await (0, config_1.getDefaultScope)() || 'project');
|
|
406
406
|
result.scope = scope;
|
|
407
407
|
// Build skill content with header
|
|
408
408
|
const skillContent = `# ${skillData.name}
|
|
@@ -495,7 +495,10 @@ ${skillData.prompt}
|
|
|
495
495
|
for (const tool of installed) {
|
|
496
496
|
log(` - ${tool}\n`);
|
|
497
497
|
}
|
|
498
|
-
log(`\
|
|
498
|
+
log(`\nLocations:\n`);
|
|
499
|
+
for (const file of result.files) {
|
|
500
|
+
log(` - ${file.tool}: ${file.path}\n`);
|
|
501
|
+
}
|
|
499
502
|
}
|
|
500
503
|
});
|
|
501
504
|
// orch skill uninstall <skill>
|
|
@@ -503,7 +506,7 @@ ${skillData.prompt}
|
|
|
503
506
|
.command('uninstall <skill>')
|
|
504
507
|
.description('Uninstall skill from local AI tool directories')
|
|
505
508
|
.option('--global', 'Uninstall from home directory (default: current directory)')
|
|
506
|
-
.option('--scope <scope>', 'Uninstall scope: user or project'
|
|
509
|
+
.option('--scope <scope>', 'Uninstall scope: user or project')
|
|
507
510
|
.option('--json', 'Output result as JSON')
|
|
508
511
|
.action(async (skillRef, options) => {
|
|
509
512
|
const jsonMode = options.json === true;
|
|
@@ -530,8 +533,8 @@ ${skillData.prompt}
|
|
|
530
533
|
throw new errors_1.CliError(errMsg);
|
|
531
534
|
}
|
|
532
535
|
result.skill = `${org}/${parsed.skill}`;
|
|
533
|
-
// Determine scope
|
|
534
|
-
const scope = options.global ? 'user' : (options.scope || 'project');
|
|
536
|
+
// Determine scope (--global is legacy alias for --scope user; then config default; then 'project')
|
|
537
|
+
const scope = options.global ? 'user' : (options.scope || await (0, config_1.getDefaultScope)() || 'project');
|
|
535
538
|
result.scope = scope;
|
|
536
539
|
// Remove from all AI tool directories
|
|
537
540
|
for (const formatId of config_1.VALID_FORMAT_IDS) {
|
package/dist/commands/star.js
CHANGED
|
@@ -33,9 +33,16 @@ function registerStarCommand(program) {
|
|
|
33
33
|
process.stdout.write(`Removed star from ${org}/${name}/${version}\n`);
|
|
34
34
|
}
|
|
35
35
|
else {
|
|
36
|
-
await (0, api_1.starAgent)(config, agentInfo.id);
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
const result = await (0, api_1.starAgent)(config, agentInfo.id);
|
|
37
|
+
if (result.starred) {
|
|
38
|
+
await (0, analytics_1.track)('cli_star', { agent: `${org}/${name}/${version}` });
|
|
39
|
+
process.stdout.write(`Starred ${org}/${name}/${version}\n`);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
// Already starred — toggle off
|
|
43
|
+
await (0, api_1.unstarAgent)(config, agentInfo.id);
|
|
44
|
+
process.stdout.write(`Unstarred ${org}/${name}/${version}\n`);
|
|
45
|
+
}
|
|
39
46
|
}
|
|
40
47
|
});
|
|
41
48
|
}
|
package/dist/commands/update.js
CHANGED
|
@@ -53,100 +53,135 @@ function registerUpdateCommand(program) {
|
|
|
53
53
|
process.stdout.write(`Agent "${agentRef}" is not installed.\n`);
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
56
|
-
|
|
56
|
+
// Group installed entries by agent name to avoid duplicates
|
|
57
|
+
// (same agent installed to multiple formats shows once)
|
|
58
|
+
const grouped = new Map();
|
|
59
|
+
for (const item of toCheck) {
|
|
60
|
+
const existing = grouped.get(item.agent);
|
|
61
|
+
if (existing) {
|
|
62
|
+
existing.push(item);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
grouped.set(item.agent, [item]);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
process.stdout.write(`Checking ${grouped.size} installed agent(s) for updates...\n\n`);
|
|
57
69
|
let updatesAvailable = 0;
|
|
58
70
|
let updatesApplied = 0;
|
|
59
71
|
let skippedModified = 0;
|
|
60
72
|
let skippedMissing = 0;
|
|
61
|
-
for (const
|
|
62
|
-
// Check
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
73
|
+
for (const [agentName, entries] of grouped) {
|
|
74
|
+
// Check file status for all entries in this group
|
|
75
|
+
const fileStatuses = [];
|
|
76
|
+
for (const item of entries) {
|
|
77
|
+
fileStatuses.push({ item, status: await (0, installed_1.checkModified)(item) });
|
|
78
|
+
}
|
|
79
|
+
// Fetch latest version once per agent
|
|
80
|
+
const latest = await fetchLatestAgent(resolved, agentName);
|
|
66
81
|
if (!latest) {
|
|
67
|
-
process.stdout.write(` ${chalk_1.default.yellow('?')} ${
|
|
82
|
+
process.stdout.write(` ${chalk_1.default.yellow('?')} ${agentName} - could not fetch latest\n`);
|
|
68
83
|
continue;
|
|
69
84
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
85
|
+
// Use the version from the first entry (all entries for the same
|
|
86
|
+
// agent should share the same version after install/update)
|
|
87
|
+
const installedVersion = entries[0].version;
|
|
88
|
+
const hasUpdate = latest.latestVersion !== installedVersion;
|
|
89
|
+
const anyMissing = fileStatuses.some(f => f.status.missing);
|
|
90
|
+
const anyModified = fileStatuses.some(f => f.status.modified);
|
|
91
|
+
if (!hasUpdate && !anyModified && !anyMissing) {
|
|
92
|
+
const formatSuffix = entries.length > 1
|
|
93
|
+
? ` ${chalk_1.default.dim(`(${entries.map(e => e.format).join(', ')})`)}`
|
|
94
|
+
: '';
|
|
95
|
+
process.stdout.write(` ${chalk_1.default.green('✓')} ${agentName}@${installedVersion} - up to date${formatSuffix}\n`);
|
|
73
96
|
continue;
|
|
74
97
|
}
|
|
75
|
-
// Handle missing
|
|
76
|
-
if (
|
|
77
|
-
|
|
98
|
+
// Handle missing files without --force
|
|
99
|
+
if (anyMissing && !hasUpdate && !options.force) {
|
|
100
|
+
const missingFormats = fileStatuses.filter(f => f.status.missing).map(f => f.item.format);
|
|
101
|
+
process.stdout.write(` ${chalk_1.default.yellow('!')} ${agentName} - file missing [${missingFormats.join(', ')}] (use --force to reinstall)\n`);
|
|
78
102
|
skippedMissing++;
|
|
79
103
|
continue;
|
|
80
104
|
}
|
|
81
|
-
// Handle modified
|
|
82
|
-
if (
|
|
83
|
-
|
|
105
|
+
// Handle modified files without --force
|
|
106
|
+
if (anyModified && !hasUpdate && !options.force) {
|
|
107
|
+
const modifiedFormats = fileStatuses.filter(f => f.status.modified).map(f => f.item.format);
|
|
108
|
+
process.stdout.write(` ${chalk_1.default.yellow('!')} ${agentName} - local modifications [${modifiedFormats.join(', ')}] (use --force to overwrite)\n`);
|
|
84
109
|
skippedModified++;
|
|
85
110
|
continue;
|
|
86
111
|
}
|
|
87
|
-
if (hasUpdate ||
|
|
112
|
+
if (hasUpdate || anyMissing) {
|
|
88
113
|
if (hasUpdate) {
|
|
89
114
|
updatesAvailable++;
|
|
90
115
|
}
|
|
91
|
-
process.stdout.write(` ${chalk_1.default.blue('↑')} ${
|
|
92
|
-
if (
|
|
116
|
+
process.stdout.write(` ${chalk_1.default.blue('↑')} ${agentName}@${installedVersion} → ${latest.latestVersion}`);
|
|
117
|
+
if (anyModified) {
|
|
93
118
|
process.stdout.write(` ${chalk_1.default.yellow('(modified)')}`);
|
|
94
119
|
}
|
|
95
|
-
if (
|
|
120
|
+
if (anyMissing) {
|
|
96
121
|
process.stdout.write(` ${chalk_1.default.yellow('(reinstalling)')}`);
|
|
97
122
|
}
|
|
98
123
|
process.stdout.write('\n');
|
|
99
124
|
if (options.check) {
|
|
100
125
|
continue;
|
|
101
126
|
}
|
|
102
|
-
// Apply update
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
127
|
+
// Apply update to each format entry
|
|
128
|
+
for (const { item, status: fileStatus } of fileStatuses) {
|
|
129
|
+
// Skip unmodified and non-missing entries if no version update
|
|
130
|
+
if (!hasUpdate && !fileStatus.missing)
|
|
131
|
+
continue;
|
|
132
|
+
// Skip modified entries without --force
|
|
133
|
+
if (fileStatus.modified && !options.force) {
|
|
134
|
+
process.stderr.write(` Skipped ${item.format}: local modifications (use --force)\n`);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const adapter = adapters_1.adapterRegistry.get(item.format);
|
|
138
|
+
if (!adapter) {
|
|
139
|
+
process.stderr.write(` Skipped ${item.format}: unknown format\n`);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
const checkResult = adapter.canConvert(latest.agent);
|
|
143
|
+
if (!checkResult.canConvert) {
|
|
144
|
+
process.stderr.write(` Skipped ${item.format}: ${checkResult.errors.join(', ')}\n`);
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
const files = adapter.convert(latest.agent);
|
|
148
|
+
if (files.length > 1) {
|
|
149
|
+
process.stderr.write(` Skipped ${item.format}: multi-file adapters not supported for update. Reinstall instead.\n`);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
for (const file of files) {
|
|
153
|
+
// Use the original path from tracking
|
|
154
|
+
const fullPath = item.path;
|
|
155
|
+
try {
|
|
156
|
+
const dir = path_1.default.dirname(fullPath);
|
|
157
|
+
await promises_1.default.mkdir(dir, { recursive: true });
|
|
158
|
+
// Special handling for AGENTS.md - append/replace instead of overwrite
|
|
159
|
+
if (file.filename === 'AGENTS.md') {
|
|
160
|
+
let existingContent = '';
|
|
161
|
+
try {
|
|
162
|
+
existingContent = await promises_1.default.readFile(fullPath, 'utf-8');
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
// File doesn't exist, will create new
|
|
166
|
+
}
|
|
167
|
+
file.content = (0, agents_md_utils_1.mergeAgentsMdContent)(existingContent, file.content, item.agent);
|
|
132
168
|
}
|
|
133
|
-
|
|
169
|
+
await promises_1.default.writeFile(fullPath, file.content);
|
|
170
|
+
// Update tracking
|
|
171
|
+
const updatedItem = {
|
|
172
|
+
...item,
|
|
173
|
+
version: latest.latestVersion,
|
|
174
|
+
installedAt: new Date().toISOString(),
|
|
175
|
+
adapterVersion: adapter.version,
|
|
176
|
+
contentHash: (0, installed_1.computeHash)(file.content),
|
|
177
|
+
};
|
|
178
|
+
await (0, installed_1.trackInstall)(updatedItem);
|
|
179
|
+
process.stdout.write(` Updated: ${fullPath}\n`);
|
|
180
|
+
updatesApplied++;
|
|
181
|
+
}
|
|
182
|
+
catch (err) {
|
|
183
|
+
process.stderr.write(` Error (${item.format}): ${err.message}\n`);
|
|
134
184
|
}
|
|
135
|
-
await promises_1.default.writeFile(fullPath, file.content);
|
|
136
|
-
// Update tracking
|
|
137
|
-
const updatedItem = {
|
|
138
|
-
...item,
|
|
139
|
-
version: latest.latestVersion,
|
|
140
|
-
installedAt: new Date().toISOString(),
|
|
141
|
-
adapterVersion: adapter.version,
|
|
142
|
-
contentHash: (0, installed_1.computeHash)(file.content),
|
|
143
|
-
};
|
|
144
|
-
await (0, installed_1.trackInstall)(updatedItem);
|
|
145
|
-
process.stdout.write(` Updated: ${fullPath}\n`);
|
|
146
|
-
updatesApplied++;
|
|
147
|
-
}
|
|
148
|
-
catch (err) {
|
|
149
|
-
process.stderr.write(` Error: ${err.message}\n`);
|
|
150
185
|
}
|
|
151
186
|
}
|
|
152
187
|
}
|
package/dist/commands/whoami.js
CHANGED
|
@@ -13,6 +13,24 @@ function registerWhoamiCommand(program) {
|
|
|
13
13
|
process.stdout.write(`Logged in as: ${org.name}\n`);
|
|
14
14
|
process.stdout.write(`Org slug: ${org.slug}\n`);
|
|
15
15
|
process.stdout.write(`API URL: ${config.apiUrl}\n`);
|
|
16
|
+
// Show active workspace if one is set
|
|
17
|
+
const configFile = await (0, config_1.loadConfig)();
|
|
18
|
+
if (configFile.workspace) {
|
|
19
|
+
try {
|
|
20
|
+
const response = await (0, api_1.request)(config, 'GET', '/workspaces');
|
|
21
|
+
const workspace = response.workspaces.find((w) => w.slug === configFile.workspace);
|
|
22
|
+
if (workspace) {
|
|
23
|
+
process.stdout.write(`Active workspace: ${workspace.name} (${workspace.slug})\n`);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
process.stdout.write(`Active workspace: ${configFile.workspace} (not found)\n`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// Workspace fetch failed - show slug only
|
|
31
|
+
process.stdout.write(`Active workspace: ${configFile.workspace}\n`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
16
34
|
// Show balance after org info
|
|
17
35
|
try {
|
|
18
36
|
const balance = await (0, api_1.getCreditsBalance)(config);
|
package/dist/index.js
CHANGED
|
@@ -47,8 +47,10 @@ const errors_1 = require("./lib/errors");
|
|
|
47
47
|
const analytics_1 = require("./lib/analytics");
|
|
48
48
|
const config_1 = require("./lib/config");
|
|
49
49
|
const spinner_1 = require("./lib/spinner");
|
|
50
|
+
const update_notifier_1 = require("./lib/update-notifier");
|
|
50
51
|
const package_json_1 = __importDefault(require("../package.json"));
|
|
51
52
|
(0, analytics_1.initPostHog)();
|
|
53
|
+
(0, update_notifier_1.checkForUpdates)();
|
|
52
54
|
const program = new commander_1.Command();
|
|
53
55
|
program
|
|
54
56
|
.name('orchagent')
|
|
@@ -89,4 +91,7 @@ async function main() {
|
|
|
89
91
|
}
|
|
90
92
|
main()
|
|
91
93
|
.catch(errors_1.exitWithError)
|
|
92
|
-
.finally(() =>
|
|
94
|
+
.finally(() => {
|
|
95
|
+
(0, update_notifier_1.printUpdateNotification)();
|
|
96
|
+
return (0, analytics_1.shutdownPostHog)();
|
|
97
|
+
});
|