@orchagent/cli 0.3.89 → 0.3.91
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/completion.js +379 -0
- package/dist/commands/dag.js +16 -7
- package/dist/commands/delete.js +9 -4
- package/dist/commands/diff.js +10 -2
- package/dist/commands/estimate.js +5 -2
- package/dist/commands/fork.js +7 -1
- package/dist/commands/index.js +2 -0
- package/dist/commands/info.js +8 -1
- package/dist/commands/init-wizard.js +160 -0
- package/dist/commands/init.js +38 -2
- package/dist/commands/login.js +8 -0
- package/dist/commands/logs.js +17 -7
- package/dist/commands/metrics.js +16 -7
- package/dist/commands/replay.js +16 -7
- package/dist/commands/run.js +51 -4
- package/dist/commands/schedule.js +72 -8
- package/dist/commands/secrets.js +16 -7
- package/dist/commands/service.js +16 -7
- package/dist/commands/skill.js +84 -8
- package/dist/commands/trace.js +16 -7
- package/dist/commands/tree.js +7 -1
- package/dist/commands/workspace.js +16 -7
- package/dist/lib/agent-ref.js +4 -1
- package/dist/lib/api.js +2 -8
- package/dist/lib/browser-auth.js +1 -0
- package/dist/lib/doctor/checks/environment.js +44 -1
- package/package.json +1 -1
package/dist/commands/skill.js
CHANGED
|
@@ -40,11 +40,13 @@ exports.registerSkillCommand = registerSkillCommand;
|
|
|
40
40
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
41
41
|
const path_1 = __importDefault(require("path"));
|
|
42
42
|
const os_1 = __importDefault(require("os"));
|
|
43
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
43
44
|
const config_1 = require("../lib/config");
|
|
44
45
|
const api_1 = require("../lib/api");
|
|
45
46
|
const errors_1 = require("../lib/errors");
|
|
46
47
|
const analytics_1 = require("../lib/analytics");
|
|
47
48
|
const installed_1 = require("../lib/installed");
|
|
49
|
+
const agents_1 = require("./agents");
|
|
48
50
|
const package_json_1 = __importDefault(require("../../package.json"));
|
|
49
51
|
const DEFAULT_VERSION = 'latest';
|
|
50
52
|
function stripFrontmatter(content) {
|
|
@@ -208,15 +210,89 @@ function registerSkillCommand(program) {
|
|
|
208
210
|
// orch skill list
|
|
209
211
|
skill
|
|
210
212
|
.command('list')
|
|
211
|
-
.description('
|
|
213
|
+
.description('List your published and installed skills')
|
|
212
214
|
.option('--json', 'Output raw JSON')
|
|
213
|
-
.action(async () => {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
215
|
+
.action(async (options) => {
|
|
216
|
+
const config = await (0, config_1.getResolvedConfig)();
|
|
217
|
+
const jsonMode = options.json === true;
|
|
218
|
+
// Fetch published skills (only if authenticated)
|
|
219
|
+
let publishedSkills = [];
|
|
220
|
+
if (config.apiKey) {
|
|
221
|
+
const configFile = await (0, config_1.loadConfig)();
|
|
222
|
+
const orgSlug = configFile.workspace ?? config.defaultOrg;
|
|
223
|
+
const workspaceId = orgSlug ? await (0, api_1.resolveWorkspaceIdForOrg)(config, orgSlug) : undefined;
|
|
224
|
+
const allAgents = await (0, api_1.listMyAgents)(config, workspaceId);
|
|
225
|
+
publishedSkills = allAgents.filter(a => a.type === 'skill');
|
|
226
|
+
}
|
|
227
|
+
// Fetch locally installed skills
|
|
228
|
+
const installed = await (0, installed_1.getInstalled)();
|
|
229
|
+
// JSON output
|
|
230
|
+
if (jsonMode) {
|
|
231
|
+
const { agents: latestSkills } = (0, agents_1.latestOnly)(publishedSkills);
|
|
232
|
+
process.stdout.write(JSON.stringify({
|
|
233
|
+
published: latestSkills,
|
|
234
|
+
installed,
|
|
235
|
+
}, null, 2) + '\n');
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
// Empty state
|
|
239
|
+
if (publishedSkills.length === 0 && installed.length === 0) {
|
|
240
|
+
process.stdout.write('No skills found.\n\n' +
|
|
241
|
+
'Install a skill:\n' +
|
|
242
|
+
' orch skill install <org>/<skill-name>\n\n' +
|
|
243
|
+
'Create a skill:\n' +
|
|
244
|
+
' orch skill create <name>\n');
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
// Published skills table
|
|
248
|
+
if (publishedSkills.length > 0) {
|
|
249
|
+
const { agents: latestSkills, versionCounts } = (0, agents_1.latestOnly)(publishedSkills);
|
|
250
|
+
const Table = (await Promise.resolve().then(() => __importStar(require('cli-table3')))).default;
|
|
251
|
+
const table = new Table({
|
|
252
|
+
head: [
|
|
253
|
+
chalk_1.default.bold('Skill'),
|
|
254
|
+
chalk_1.default.bold('Version'),
|
|
255
|
+
chalk_1.default.bold('Description'),
|
|
256
|
+
],
|
|
257
|
+
});
|
|
258
|
+
for (const skill of latestSkills) {
|
|
259
|
+
const desc = skill.description
|
|
260
|
+
? skill.description.length > 60
|
|
261
|
+
? skill.description.slice(0, 57) + '...'
|
|
262
|
+
: skill.description
|
|
263
|
+
: '-';
|
|
264
|
+
let version = skill.version;
|
|
265
|
+
const count = versionCounts.get(skill.name) ?? 1;
|
|
266
|
+
if (count > 1) {
|
|
267
|
+
version = `${skill.version} (${count} total)`;
|
|
268
|
+
}
|
|
269
|
+
table.push([skill.name, version, desc]);
|
|
270
|
+
}
|
|
271
|
+
process.stdout.write(`Published Skills\n${table.toString()}\n`);
|
|
272
|
+
process.stdout.write(`\n${latestSkills.length} skill${latestSkills.length === 1 ? '' : 's'}`);
|
|
273
|
+
if (publishedSkills.length > latestSkills.length) {
|
|
274
|
+
process.stdout.write(` (${publishedSkills.length} versions total)`);
|
|
275
|
+
}
|
|
276
|
+
process.stdout.write('\n');
|
|
277
|
+
}
|
|
278
|
+
// Installed skills table
|
|
279
|
+
if (installed.length > 0) {
|
|
280
|
+
const Table = (await Promise.resolve().then(() => __importStar(require('cli-table3')))).default;
|
|
281
|
+
const table = new Table({
|
|
282
|
+
head: [
|
|
283
|
+
chalk_1.default.bold('Skill'),
|
|
284
|
+
chalk_1.default.bold('Version'),
|
|
285
|
+
chalk_1.default.bold('Tool'),
|
|
286
|
+
chalk_1.default.bold('Scope'),
|
|
287
|
+
],
|
|
288
|
+
});
|
|
289
|
+
for (const entry of installed) {
|
|
290
|
+
table.push([entry.agent, entry.version, entry.format, entry.scope]);
|
|
291
|
+
}
|
|
292
|
+
if (publishedSkills.length > 0)
|
|
293
|
+
process.stdout.write('\n');
|
|
294
|
+
process.stdout.write(`Installed Skills\n${table.toString()}\n`);
|
|
295
|
+
}
|
|
220
296
|
});
|
|
221
297
|
// orch skill create [name]
|
|
222
298
|
skill
|
package/dist/commands/trace.js
CHANGED
|
@@ -15,15 +15,24 @@ const output_1 = require("../lib/output");
|
|
|
15
15
|
async function resolveWorkspaceId(config, slug) {
|
|
16
16
|
const configFile = await (0, config_1.loadConfig)();
|
|
17
17
|
const targetSlug = slug ?? configFile.workspace;
|
|
18
|
-
if (!targetSlug) {
|
|
19
|
-
throw new errors_1.CliError('No workspace specified. Use --workspace <slug> or run `orch workspace use <slug>` first.');
|
|
20
|
-
}
|
|
21
18
|
const response = await (0, api_1.request)(config, 'GET', '/workspaces');
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
if (targetSlug) {
|
|
20
|
+
const workspace = response.workspaces.find((w) => w.slug === targetSlug);
|
|
21
|
+
if (!workspace) {
|
|
22
|
+
throw new errors_1.CliError(`Workspace '${targetSlug}' not found.`);
|
|
23
|
+
}
|
|
24
|
+
return workspace.id;
|
|
25
|
+
}
|
|
26
|
+
// No workspace specified — auto-select if user has exactly one
|
|
27
|
+
if (response.workspaces.length === 0) {
|
|
28
|
+
throw new errors_1.CliError('No workspaces found. Create one with `orch workspace create <name>`.');
|
|
29
|
+
}
|
|
30
|
+
if (response.workspaces.length === 1) {
|
|
31
|
+
return response.workspaces[0].id;
|
|
25
32
|
}
|
|
26
|
-
|
|
33
|
+
const slugs = response.workspaces.map((w) => w.slug).join(', ');
|
|
34
|
+
throw new errors_1.CliError(`Multiple workspaces available: ${slugs}\n` +
|
|
35
|
+
'Specify one with --workspace <slug> or run `orch workspace use <slug>`.');
|
|
27
36
|
}
|
|
28
37
|
function isUuid(value) {
|
|
29
38
|
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
|
package/dist/commands/tree.js
CHANGED
|
@@ -20,7 +20,13 @@ function registerTreeCommand(program) {
|
|
|
20
20
|
if (!config.apiKey) {
|
|
21
21
|
throw new errors_1.CliError('Authentication required. Run: orch login');
|
|
22
22
|
}
|
|
23
|
-
const
|
|
23
|
+
const parsed = (0, agent_ref_1.parseAgentRef)(agentArg);
|
|
24
|
+
const configFile = await (0, config_1.loadConfig)();
|
|
25
|
+
const org = parsed.org ?? configFile.workspace ?? config.defaultOrg;
|
|
26
|
+
if (!org) {
|
|
27
|
+
throw new errors_1.CliError('Missing org. Use org/agent format or set default org.');
|
|
28
|
+
}
|
|
29
|
+
const { agent, version } = parsed;
|
|
24
30
|
const tree = await (0, api_1.request)(config, 'GET', `/agents/${org}/${agent}/${version}/tree`);
|
|
25
31
|
if (options.json) {
|
|
26
32
|
console.log(JSON.stringify(tree, null, 2));
|
|
@@ -16,15 +16,24 @@ function deriveSlug(name) {
|
|
|
16
16
|
async function resolveWorkspaceId(config, slug) {
|
|
17
17
|
const configFile = await (0, config_1.loadConfig)();
|
|
18
18
|
const targetSlug = slug ?? configFile.workspace;
|
|
19
|
-
if (!targetSlug) {
|
|
20
|
-
throw new errors_1.CliError('No workspace specified. Use --workspace <slug> or run `orchagent workspace use <slug>` first.');
|
|
21
|
-
}
|
|
22
19
|
const response = await (0, api_1.request)(config, 'GET', '/workspaces');
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
if (targetSlug) {
|
|
21
|
+
const workspace = response.workspaces.find((w) => w.slug === targetSlug);
|
|
22
|
+
if (!workspace) {
|
|
23
|
+
throw new errors_1.CliError(`Workspace '${targetSlug}' not found.`);
|
|
24
|
+
}
|
|
25
|
+
return workspace.id;
|
|
26
|
+
}
|
|
27
|
+
// No workspace specified — auto-select if user has exactly one
|
|
28
|
+
if (response.workspaces.length === 0) {
|
|
29
|
+
throw new errors_1.CliError('No workspaces found. Create one with `orch workspace create <name>`.');
|
|
30
|
+
}
|
|
31
|
+
if (response.workspaces.length === 1) {
|
|
32
|
+
return response.workspaces[0].id;
|
|
26
33
|
}
|
|
27
|
-
|
|
34
|
+
const slugs = response.workspaces.map((w) => w.slug).join(', ');
|
|
35
|
+
throw new errors_1.CliError(`Multiple workspaces available: ${slugs}\n` +
|
|
36
|
+
'Specify one with --workspace <slug> or run `orch workspace use <slug>`.');
|
|
28
37
|
}
|
|
29
38
|
async function listWorkspaces(config, options) {
|
|
30
39
|
const response = await (0, api_1.request)(config, 'GET', '/workspaces');
|
package/dist/lib/agent-ref.js
CHANGED
|
@@ -6,8 +6,11 @@ function parseAgentRef(value, defaultVersion = 'latest') {
|
|
|
6
6
|
const [ref, versionPart] = value.split('@');
|
|
7
7
|
const version = versionPart?.trim() || defaultVersion;
|
|
8
8
|
const segments = ref.split('/');
|
|
9
|
+
if (segments.length === 1) {
|
|
10
|
+
return { org: undefined, agent: segments[0], version };
|
|
11
|
+
}
|
|
9
12
|
if (segments.length === 2) {
|
|
10
13
|
return { org: segments[0], agent: segments[1], version };
|
|
11
14
|
}
|
|
12
|
-
throw new errors_1.CliError('Invalid agent reference. Use org/agent[@version] format');
|
|
15
|
+
throw new errors_1.CliError('Invalid agent reference. Use agent or org/agent[@version] format');
|
|
13
16
|
}
|
package/dist/lib/api.js
CHANGED
|
@@ -116,8 +116,6 @@ async function safeFetchWithRetryForCalls(url, options) {
|
|
|
116
116
|
parsed = JSON.parse(bodyText);
|
|
117
117
|
}
|
|
118
118
|
catch { /* ignore */ }
|
|
119
|
-
const detail = parsed?.error?.message ||
|
|
120
|
-
parsed?.message || '';
|
|
121
119
|
const isRetryable = parsed?.error?.is_retryable;
|
|
122
120
|
// Don't retry if server explicitly says error is not retryable
|
|
123
121
|
if (isRetryable === false) {
|
|
@@ -130,8 +128,7 @@ async function safeFetchWithRetryForCalls(url, options) {
|
|
|
130
128
|
if (attempt < MAX_RETRIES) {
|
|
131
129
|
const delay = BASE_DELAY_MS * Math.pow(2, attempt - 1);
|
|
132
130
|
const jitter = Math.random() * 500;
|
|
133
|
-
|
|
134
|
-
process.stderr.write(`Request failed (${response.status}${detailSuffix}), retrying in ${Math.round((delay + jitter) / 1000)}s...\n`);
|
|
131
|
+
process.stderr.write(`Server error (${response.status}), retrying in ${Math.round((delay + jitter) / 1000)}s...\n`);
|
|
135
132
|
await new Promise(r => setTimeout(r, delay + jitter));
|
|
136
133
|
continue;
|
|
137
134
|
}
|
|
@@ -174,8 +171,6 @@ async function safeFetchWithRetry(url, options) {
|
|
|
174
171
|
parsed = JSON.parse(bodyText);
|
|
175
172
|
}
|
|
176
173
|
catch { /* ignore */ }
|
|
177
|
-
const detail = parsed?.error?.message ||
|
|
178
|
-
parsed?.message || '';
|
|
179
174
|
const isRetryable = parsed?.error?.is_retryable;
|
|
180
175
|
// Don't retry if server explicitly says error is not retryable
|
|
181
176
|
if (isRetryable === false) {
|
|
@@ -188,8 +183,7 @@ async function safeFetchWithRetry(url, options) {
|
|
|
188
183
|
if (attempt < MAX_RETRIES) {
|
|
189
184
|
const delay = BASE_DELAY_MS * Math.pow(2, attempt - 1);
|
|
190
185
|
const jitter = Math.random() * 500;
|
|
191
|
-
|
|
192
|
-
process.stderr.write(`Request failed (${response.status}${detailSuffix}), retrying in ${Math.round((delay + jitter) / 1000)}s...\n`);
|
|
186
|
+
process.stderr.write(`Server error (${response.status}), retrying in ${Math.round((delay + jitter) / 1000)}s...\n`);
|
|
193
187
|
await new Promise(r => setTimeout(r, delay + jitter));
|
|
194
188
|
continue;
|
|
195
189
|
}
|
package/dist/lib/browser-auth.js
CHANGED
|
@@ -191,6 +191,37 @@ function safeRealpathSync(p) {
|
|
|
191
191
|
return p;
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
|
+
/**
|
|
195
|
+
* Parse a version string into a comparable numeric tuple.
|
|
196
|
+
* Returns [-1, -1, -1] for unparseable versions (sorts below all valid versions).
|
|
197
|
+
*/
|
|
198
|
+
function parseVersion(version) {
|
|
199
|
+
const match = version.match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
200
|
+
if (!match)
|
|
201
|
+
return [-1, -1, -1];
|
|
202
|
+
return [parseInt(match[1], 10), parseInt(match[2], 10), parseInt(match[3], 10)];
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Find the latest (highest) version from a list of version strings.
|
|
206
|
+
* Unparseable versions (e.g. "unknown") sort below all valid versions.
|
|
207
|
+
*/
|
|
208
|
+
function findLatestVersion(versions) {
|
|
209
|
+
let latest = versions[0];
|
|
210
|
+
let latestParts = parseVersion(latest);
|
|
211
|
+
for (let i = 1; i < versions.length; i++) {
|
|
212
|
+
const parts = parseVersion(versions[i]);
|
|
213
|
+
for (let j = 0; j < 3; j++) {
|
|
214
|
+
if (parts[j] > latestParts[j]) {
|
|
215
|
+
latest = versions[i];
|
|
216
|
+
latestParts = parts;
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
219
|
+
if (parts[j] < latestParts[j])
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return latest;
|
|
224
|
+
}
|
|
194
225
|
/**
|
|
195
226
|
* Detect multiple CLI installations at different paths/versions (BUG-008).
|
|
196
227
|
*
|
|
@@ -248,12 +279,24 @@ async function checkDualInstallation() {
|
|
|
248
279
|
.map((i) => `${i.path} (v${i.version})`)
|
|
249
280
|
.join(', ');
|
|
250
281
|
if (versionsDiffer) {
|
|
282
|
+
// Find the latest version and build a specific rm command for stale paths
|
|
283
|
+
const latestVersion = findLatestVersion(allInstalls.map((i) => i.version));
|
|
284
|
+
const stalePaths = allInstalls
|
|
285
|
+
.filter((i) => i.version !== latestVersion)
|
|
286
|
+
.map((i) => i.path);
|
|
287
|
+
const staleList = allInstalls
|
|
288
|
+
.filter((i) => i.version !== latestVersion)
|
|
289
|
+
.map((i) => `${i.path} (v${i.version})`)
|
|
290
|
+
.join(', ');
|
|
291
|
+
const fix = stalePaths.length === 1
|
|
292
|
+
? `Remove outdated ${staleList}: run \`rm ${stalePaths[0]}\``
|
|
293
|
+
: `Remove outdated installations (${staleList}): run \`rm ${stalePaths.join(' ')}\``;
|
|
251
294
|
return {
|
|
252
295
|
category: 'environment',
|
|
253
296
|
name: 'dual_installation',
|
|
254
297
|
status: 'warning',
|
|
255
298
|
message: `Multiple CLI versions found: ${pathList}`,
|
|
256
|
-
fix
|
|
299
|
+
fix,
|
|
257
300
|
details: {
|
|
258
301
|
installationCount: installations.size,
|
|
259
302
|
versionMismatch: true,
|
package/package.json
CHANGED